forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnot-found.tsx
More file actions
128 lines (113 loc) · 3.98 KB
/
Copy pathnot-found.tsx
File metadata and controls
128 lines (113 loc) · 3.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
"use client";
import { useEffect } from "react";
import { usePathname, useSearchParams } from "next/navigation";
import Link from "next/link";
import posthog from "posthog-js";
import { Home, ArrowLeft } from "lucide-react";
import { Logo } from "./logo";
function isBotUserAgent(userAgent: string): boolean {
const botPatterns = [
/bot/i,
/crawl/i,
/spider/i,
/slurp/i,
/mediapartners/i,
/googlebot/i,
/bingbot/i,
/facebookexternalhit/i,
/twitterbot/i,
];
return botPatterns.some((pattern) => pattern.test(userAgent));
}
export default function NotFound() {
const pathname = usePathname();
const searchParams = useSearchParams();
useEffect(() => {
if (typeof window === "undefined") return;
const referrer = document.referrer;
const userAgent = navigator.userAgent;
const isBot = isBotUserAgent(userAgent);
// Only track if PostHog is initialized and it's not a bot
if (posthog?.__loaded && !isBot) {
const queryString = searchParams?.toString();
const fullPath = pathname + (queryString ? `?${queryString}` : "");
// Check if referrer is internal (docs site or corporate site)
const isInternalReferrer =
referrer.includes("copilotkit.ai") || referrer.includes("localhost");
// Parse referrer URL if available
let referrerDomain = null;
let referrerPath = null;
if (referrer) {
try {
const referrerUrl = new URL(referrer);
referrerDomain = referrerUrl.hostname;
referrerPath = referrerUrl.pathname;
} catch (e) {
// Invalid URL, skip parsing
}
}
try {
posthog.capture("broken_link_accessed", {
// The broken URL
broken_url: pathname,
broken_url_full: `https://docs.copilotkit.ai${fullPath}`,
query_params: queryString || null,
// Where they came from
referrer_url: referrer || "(direct)",
referrer_domain: referrerDomain,
referrer_path: referrerPath,
is_internal_referrer: isInternalReferrer,
// Context for filtering
user_agent: userAgent,
is_likely_bot: isBot,
// Useful metadata
timestamp: new Date().toISOString(),
viewport_width: window.innerWidth,
viewport_height: window.innerHeight,
});
} catch (error) {
// Silently fail if tracking fails
if (process.env.NODE_ENV === "development") {
console.warn("Failed to track 404:", error);
}
}
}
}, [pathname, searchParams]);
return (
<div className="fixed inset-0 flex flex-col items-center justify-center p-4 bg-background z-50">
<div className="max-w-md w-full text-center space-y-8">
<div className="flex justify-center mb-8">
<div className="scale-150">
<Logo />
</div>
</div>
<div className="space-y-4">
<h1 className="text-6xl font-bold text-foreground">404</h1>
<h2 className="text-2xl font-semibold text-foreground">
Page Not Found
</h2>
<p className="text-muted-foreground">
Sorry, we couldn't find the page you're looking for. The link may be
outdated or the page may have moved.
</p>
</div>
<div className="flex gap-4 justify-center">
<Link
href="/"
className="inline-flex items-center gap-2 px-4 py-2 bg-primary text-primary-foreground rounded-md hover:opacity-90 transition-opacity font-medium"
>
<Home className="w-4 h-4" />
Go Home
</Link>
<button
onClick={() => window.history.back()}
className="inline-flex items-center gap-2 px-4 py-2 bg-secondary text-secondary-foreground rounded-md hover:bg-accent transition-colors font-medium"
>
<ArrowLeft className="w-4 h-4" />
Go Back
</button>
</div>
</div>
</div>
);
}