import type { AdminViewServerProps } from "payload"; import Link from "next/link"; import { canViewAnalytics } from "@/access"; import { RANGE_OPTIONS, resolveRange } from "@/lib/analytics/range"; import { getDashboardComparison, percentDelta, type DashboardStats } from "@/lib/analytics/dashboardQueries"; import { topEntries } from "@/lib/analytics/aggregate"; import { analyticsEventLabel } from "@/lib/analytics/events"; import { AnalyticsChart } from "./AnalyticsChart"; import styles from "./AdminAnalyticsView.module.css"; const DEVICE_LABELS: Record = { mobile: "Handy", desktop: "Computer", tablet: "Tablet" }; const BROWSER_LABELS: Record = { chrome: "Chrome", firefox: "Firefox", safari: "Safari", edge: "Edge", other: "Sonstige" }; function fmtInt(n: number): string { return n.toLocaleString("de-DE"); } function DeltaBadge({ delta }: { delta: number | null }) { if (delta === null) return null; const cls = delta > 0 ? styles.deltaUp : delta < 0 ? styles.deltaDown : styles.deltaFlat; const arrow = delta > 0 ? "↑" : delta < 0 ? "↓" : "→"; return (

{arrow} {Math.abs(delta).toLocaleString("de-DE")}%

); } function Tile({ label, value, delta }: { label: string; value: number; delta: number | null | undefined }) { return (

{label}

{fmtInt(value)}

{delta !== undefined && }
); } function EntryTable({ title, entries }: { title: string; entries: [string, number][] }) { return (

{title}

{entries.length === 0 ? (

Keine Daten in diesem Zeitraum.

) : ( {entries.map(([key, count]) => ( ))}
{key} {fmtInt(count)}
)}
); } function buildHref(base: URLSearchParams, overrides: Record): string { const params = new URLSearchParams(base); for (const [key, value] of Object.entries(overrides)) { if (value === null) params.delete(key); else params.set(key, value); } const qs = params.toString(); return qs ? `?${qs}` : "?"; } export async function AdminAnalyticsView({ initPageResult }: AdminViewServerProps) { const req = initPageResult.req; if (!canViewAnalytics({ req })) { return (
Zur Übersicht

Auswertung

Du hast keine Berechtigung, diesen Bereich zu sehen.

); } const settings = await req.payload.findGlobal({ slug: "analytics-settings" }); const maxDaysBack = settings.rawRetentionDays ?? 90; const searchParams = req.searchParams; const compareEnabled = searchParams.get("compare") === "1"; const { key: activeRange, range, compareRange } = resolveRange(searchParams, maxDaysBack); const { current, previous }: { current: DashboardStats; previous: DashboardStats } = await getDashboardComparison( req.payload, range, compareRange, ); const delta = (metric: keyof Pick) => compareEnabled ? percentDelta(current[metric], previous[metric]) : undefined; const eventDelta = (name: string) => compareEnabled ? percentDelta(current.eventCounts[name] ?? 0, previous.eventCounts[name] ?? 0) : undefined; const fromParam = range.from.toISOString().slice(0, 10); const toParam = range.to.toISOString().slice(0, 10); return (
Zur Übersicht

Auswertung

Datensparsame Reichweitenmessung ohne personenbezogene Profile. Rohdaten werden {maxDaysBack} Tage aufbewahrt.

{RANGE_OPTIONS.map((option) => ( {option.label} ))}
{compareEnabled && } bis
{RANGE_OPTIONS.some((o) => typeof o.days === "number" && o.days > maxDaysBack) && (

Zeiträume sind auf die konfigurierte Rohdaten-Aufbewahrung von {maxDaysBack} Tagen begrenzt (siehe „Auswertungs-Einstellungen“).

)}

Seitenaufrufe und Besuche

[analyticsEventLabel(name), count])} /> [DEVICE_LABELS[key] ?? key, count])} /> [BROWSER_LABELS[key] ?? key, count])} />

Auswertung und Datenschutz

Erhobene Daten:

  • Seitenaufrufe und Ereignisse (siehe Tabelle „Ereignisse“)
  • Gerätetyp (Handy/Computer/Tablet)
  • Browser-Familie
  • Referrer-Hostname (nur die Domain, keine vollständige URL)

Keine Namen, E-Mail-Adressen, Telefonnummern, vollständigen IP-Adressen oder Formularinhalte. Kein Fingerprinting, keine dauerhaften individuellen Nutzerprofile - Besucher werden über einen täglich rotierenden, nicht zurückverfolgbaren Hash gruppiert.

Aufbewahrung: {settings.rawRetentionDays} Tage für Rohdaten, {settings.aggregateRetentionMonths} Monate für aggregierte Tagesstatistiken (konfigurierbar unter „Auswertungs-Einstellungen“).

Rechtliche Einordnung (z. B. ob dies für eure Website ausreichend ist) ist keine technische Aussage dieses Panels - bitte im Zweifel rechtlich prüfen lassen, wie auch beim Impressum/Datenschutztext der Website.

); }