Adds a first-party analytics system with no third-party trackers and no persistent per-visitor identifiers: events are grouped into sessions via a daily-rotating pseudonymous hash (IP+UA+host, HMAC-salted, never stored raw). - New "Analytics" section in the Payload admin, gated by a canViewAnalytics permission on Users, following the existing custom-admin-view pattern used by the calendar feature - Sessions, page views, unique visitors, top/entry/exit pages, events, device/browser breakdown, date range filter with period comparison - Raw events and daily aggregate rollups as their own collections, with configurable retention and a cron endpoint that rolls up before purging - Cookie consent banner (necessary/preferences/statistics) with categories and copy editable from a new CMS global; a track() helper that is a complete no-op without statistics consent, so nothing is ever sent before a visitor opts in - track() calls wired into the booking flow, contact form, and navigation
31 lines
934 B
TypeScript
31 lines
934 B
TypeScript
import Link from "next/link";
|
|
import type { ServerProps } from "payload";
|
|
import { canViewAnalytics } from "@/access";
|
|
|
|
export function AnalyticsNavLink({ user }: ServerProps) {
|
|
// Payload's custom views/nav links have no declarative `access` option —
|
|
// this component must gate itself (see also AdminAnalyticsView.tsx, which
|
|
// re-checks the same thing for direct navigation to /admin/analytics).
|
|
if (!canViewAnalytics({ req: { user } } as Parameters<typeof canViewAnalytics>[0])) return null;
|
|
|
|
return (
|
|
<div style={{ padding: "0 8px 8px" }}>
|
|
<Link
|
|
href="/admin/analytics"
|
|
style={{
|
|
display: "block",
|
|
padding: "8px 12px",
|
|
borderRadius: 6,
|
|
fontSize: 13,
|
|
fontWeight: 600,
|
|
color: "#8b616d",
|
|
textDecoration: "none",
|
|
border: "1px solid #e2e2e2",
|
|
}}
|
|
>
|
|
📊 Analytics
|
|
</Link>
|
|
</div>
|
|
);
|
|
}
|