feat(analytics): add blog engagement, ToC tracking, and 404 monitoring

- Added BlogEngagementTracker for reading time and completion tracking
- Added ToC click tracking in blog posts
- Added global 404 error monitoring in not-found.tsx
- Completed 'Total Transparency' suite
This commit is contained in:
2026-02-16 18:31:28 +01:00
parent 58d83a7fa1
commit 24b2be2094
4 changed files with 88 additions and 11 deletions

View File

@@ -11,6 +11,7 @@ import TableOfContents from '@/components/blog/TableOfContents';
import { mdxComponents } from '@/components/blog/MDXComponents';
import { Heading } from '@/components/ui';
import { setRequestLocale } from 'next-intl/server';
import BlogEngagementTracker from '@/components/analytics/BlogEngagementTracker';
interface BlogPostProps {
params: Promise<{
@@ -67,6 +68,12 @@ export default async function BlogPost({ params }: BlogPostProps) {
return (
<article className="bg-white min-h-screen font-sans selection:bg-primary/10 selection:text-primary">
<BlogEngagementTracker
title={post.frontmatter.title}
slug={slug}
category={post.frontmatter.category}
readingTime={getReadingTime(post.content)}
/>
{/* Featured Image Header */}
{post.frontmatter.featuredImage ? (
<div className="relative w-full h-[70vh] min-h-[500px] overflow-hidden group">

View File

@@ -1,9 +1,20 @@
import { useTranslations } from 'next-intl';
import { Container, Button, Heading } from '@/components/ui';
import Scribble from '@/components/Scribble';
import { useEffect } from 'react';
import { useAnalytics } from '@/components/analytics/useAnalytics';
import { AnalyticsEvents } from '@/components/analytics/analytics-events';
export default function NotFound() {
const t = useTranslations('Error.notFound');
const { trackEvent } = useAnalytics();
useEffect(() => {
trackEvent(AnalyticsEvents.ERROR, {
type: '404_not_found',
path: typeof window !== 'undefined' ? window.location.pathname : 'unknown',
});
}, [trackEvent]);
return (
<Container className="relative py-24 flex flex-col items-center justify-center text-center min-h-[70vh] overflow-hidden">
@@ -16,19 +27,17 @@ export default function NotFound() {
<Heading level={1} className="text-6xl md:text-8xl font-bold mb-2">
404
</Heading>
<Scribble
variant="circle"
className="w-[150%] h-[150%] -top-[25%] -left-[25%] text-accent/40"
<Scribble
variant="circle"
className="w-[150%] h-[150%] -top-[25%] -left-[25%] text-accent/40"
/>
</div>
<Heading level={2} className="text-2xl md:text-3xl font-bold mb-4 text-primary">
{t('title')}
</Heading>
<p className="text-white/60 mb-10 max-w-md text-lg">
{t('description')}
</p>
<p className="text-white/60 mb-10 max-w-md text-lg">{t('description')}</p>
<div className="flex flex-col sm:flex-row gap-4">
<Button href="/" variant="accent" size="lg">