feat(analytics): Umami website-analytics suite — world map, realtime, sessions, heatmap, pixel tracking, tracked links
Adds the read-side Umami integration queued in last week's website-analytics plan (Phases 1–6 of `docs/website-analytics-flesh-out-plan.md`): - Realtime panel polls Umami at 5s intervals; world map renders visitor origins via echarts + `public/world-map/echarts-world.json` topo. - Sessions list + session-detail-sheet drill-down (per-session event timeline pulled from `/api/v1/website-analytics`). - Weekly heatmap (day-of-week × hour-of-day) for engagement timing. - Metric-detail pages under `/[portSlug]/website-analytics/[metric]` for pageviews / referrers / events deep-dives. - Email-pixel write path: `/api/public/email-pixel/[sendId]` 1×1 GIF beacon backed by `email_open_tracking` (migration 0076); resolves inline on render in inbox. - Tracked-link redirect: `/q/[slug]` routes through `tracked_links` (migration 0077) and forwards to the canonical destination after logging the click. - Dashboard `website-glance-tile` now reads from the live Umami service instead of placeholder data. Deps: `@umami/node`, `echarts`, `echarts-for-react`, `@types/geojson`, `@types/topojson-client`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import { notFound } from 'next/navigation';
|
||||
|
||||
import { MetricDetailShell } from '@/components/website-analytics/metric-detail-shell';
|
||||
|
||||
/**
|
||||
* Full ranked-list view for one analytics metric (pages / referrers /
|
||||
* countries / browsers / os / devices). Reached via the "View all" link
|
||||
* on each top-N card. Honours the `range` (and optional `from`/`to`)
|
||||
* query params so the detail page mirrors the time window the operator
|
||||
* had selected on the parent page.
|
||||
*/
|
||||
|
||||
const VALID_METRICS = ['pages', 'referrers', 'countries', 'browsers', 'os', 'devices'] as const;
|
||||
type ValidMetric = (typeof VALID_METRICS)[number];
|
||||
|
||||
interface PageProps {
|
||||
params: Promise<{ portSlug: string; metric: string }>;
|
||||
searchParams: Promise<{ range?: string; from?: string; to?: string }>;
|
||||
}
|
||||
|
||||
export default async function Page({ params, searchParams }: PageProps) {
|
||||
const { metric } = await params;
|
||||
const { range, from, to } = await searchParams;
|
||||
if (!VALID_METRICS.includes(metric as ValidMetric)) notFound();
|
||||
return (
|
||||
<MetricDetailShell
|
||||
metric={metric as ValidMetric}
|
||||
initialRange={range ?? '30d'}
|
||||
initialFrom={from}
|
||||
initialTo={to}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user