Skip to content

Commit 8324fbb

Browse files
committed
Merge branch 'preprod' of https://github.com/H1B0B0/Kick-Viewerbot into v4
2 parents d9f4ca4 + 0bd3731 commit 8324fbb

File tree

10 files changed

+1123
-28
lines changed

10 files changed

+1123
-28
lines changed

frontend/app/error/page.tsx

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
"use client";
2+
import { useEffect, useState, useRef, Suspense } from "react";
3+
import { useRouter, useSearchParams } from "next/navigation";
4+
import { Card, CardBody } from "@heroui/card";
5+
import { Button } from "@heroui/button";
6+
import { animate } from "animejs";
7+
8+
// Force dynamic rendering for this page since it uses searchParams
9+
export const dynamic = "force-dynamic";
10+
11+
export default function ErrorPage() {
12+
return (
13+
<Suspense
14+
fallback={
15+
<div className="w-full flex justify-center items-center min-h-[40vh]">
16+
Loading...
17+
</div>
18+
}
19+
>
20+
<ErrorPageContent />
21+
</Suspense>
22+
);
23+
}
24+
25+
function ErrorPageContent() {
26+
const router = useRouter();
27+
const searchParams = useSearchParams();
28+
const [mounted, setMounted] = useState(false);
29+
const errorIconRef = useRef<SVGSVGElement>(null);
30+
const cardRef = useRef<HTMLDivElement>(null);
31+
32+
// Get error message from URL params
33+
const errorMessage =
34+
searchParams.get("message") || "An error occurred during authentication";
35+
36+
useEffect(() => {
37+
setMounted(true);
38+
}, []);
39+
40+
// Animate error icon
41+
useEffect(() => {
42+
if (!mounted || !errorIconRef.current) return;
43+
44+
const circle = errorIconRef.current.querySelector("circle");
45+
const line1 = errorIconRef.current.querySelector(".line1");
46+
const line2 = errorIconRef.current.querySelector(".line2");
47+
48+
if (!circle || !line1 || !line2) return;
49+
50+
try {
51+
// Set initial state
52+
(circle as SVGCircleElement).style.strokeDasharray = "166";
53+
(circle as SVGCircleElement).style.strokeDashoffset = "166";
54+
(line1 as SVGLineElement).style.strokeDasharray = "24";
55+
(line1 as SVGLineElement).style.strokeDashoffset = "24";
56+
(line2 as SVGLineElement).style.strokeDasharray = "24";
57+
(line2 as SVGLineElement).style.strokeDashoffset = "24";
58+
59+
// Animate circle
60+
animate(circle, {
61+
strokeDashoffset: [166, 0],
62+
duration: 600,
63+
ease: "easeInOutQuad",
64+
});
65+
66+
// Animate X lines
67+
setTimeout(() => {
68+
animate(line1, {
69+
strokeDashoffset: [24, 0],
70+
duration: 300,
71+
ease: "easeInOutQuad",
72+
});
73+
animate(line2, {
74+
strokeDashoffset: [24, 0],
75+
duration: 300,
76+
ease: "easeInOutQuad",
77+
});
78+
}, 400);
79+
} catch (e) {
80+
console.warn("Animation failed:", e);
81+
}
82+
}, [mounted]);
83+
84+
// Animate card entrance
85+
useEffect(() => {
86+
if (!mounted || !cardRef.current) return;
87+
88+
try {
89+
animate(cardRef.current, {
90+
opacity: [0, 1],
91+
translateY: [20, 0],
92+
scale: [0.95, 1],
93+
duration: 600,
94+
ease: "easeOutQuad",
95+
});
96+
} catch (e) {
97+
console.warn("Card animation failed:", e);
98+
}
99+
}, [mounted]);
100+
101+
const handleGoBack = () => {
102+
router.push("/login");
103+
};
104+
105+
const handleTryAgain = () => {
106+
window.location.href = "https://api.velbots.shop/payments/patreon/redirect";
107+
};
108+
109+
if (!mounted) {
110+
return null;
111+
}
112+
113+
return (
114+
<div className="min-h-screen flex items-center justify-center p-4 relative overflow-hidden">
115+
{/* Animated background gradient */}
116+
<div className="absolute inset-0 bg-gradient-to-br from-red-500/10 via-orange-500/5 to-yellow-500/10 animate-gradient-xy" />
117+
118+
{/* Floating particles */}
119+
<div className="absolute inset-0 overflow-hidden pointer-events-none">
120+
{[...Array(15)].map((_, i) => (
121+
<div
122+
key={i}
123+
className="absolute w-2 h-2 bg-red-500/20 rounded-full animate-float"
124+
style={{
125+
left: `${Math.random() * 100}%`,
126+
top: `${Math.random() * 100}%`,
127+
animationDelay: `${Math.random() * 5}s`,
128+
animationDuration: `${5 + Math.random() * 10}s`,
129+
}}
130+
/>
131+
))}
132+
</div>
133+
134+
<Card
135+
ref={cardRef}
136+
className="relative z-10 max-w-lg w-full border-none glass-card shadow-2xl"
137+
>
138+
<CardBody className="space-y-8 p-8 md:p-12">
139+
{/* Error Icon */}
140+
<div className="flex justify-center">
141+
<div className="relative">
142+
{/* Glow effect */}
143+
<div className="absolute inset-0 bg-red-500/30 rounded-full blur-2xl animate-pulse" />
144+
145+
{/* X icon */}
146+
<svg
147+
ref={errorIconRef}
148+
className="relative w-24 h-24 md:w-32 md:h-32"
149+
viewBox="0 0 52 52"
150+
xmlns="http://www.w3.org/2000/svg"
151+
>
152+
<circle
153+
className="stroke-red-500"
154+
cx="26"
155+
cy="26"
156+
r="25"
157+
fill="none"
158+
strokeWidth="2"
159+
/>
160+
<line
161+
className="stroke-red-500 line1"
162+
x1="18"
163+
y1="18"
164+
x2="34"
165+
y2="34"
166+
strokeWidth="3"
167+
strokeLinecap="round"
168+
/>
169+
<line
170+
className="stroke-red-500 line2"
171+
x1="34"
172+
y1="18"
173+
x2="18"
174+
y2="34"
175+
strokeWidth="3"
176+
strokeLinecap="round"
177+
/>
178+
</svg>
179+
</div>
180+
</div>
181+
182+
{/* Error Message */}
183+
<div className="text-center space-y-4">
184+
<h1 className="text-3xl md:text-4xl font-black bg-gradient-to-r from-red-500 via-orange-400 to-yellow-400 bg-clip-text text-transparent animate-gradient-x">
185+
Oops! Something went wrong
186+
</h1>
187+
<p className="text-lg md:text-xl text-default-600 font-medium">
188+
{errorMessage}
189+
</p>
190+
</div>
191+
192+
{/* Common Causes */}
193+
<div className="space-y-3 p-6 rounded-2xl bg-gradient-to-br from-amber-500/5 to-orange-500/5 border border-amber-500/20">
194+
<h3 className="text-sm font-semibold text-default-700 uppercase tracking-wider mb-4">
195+
💡 Common causes:
196+
</h3>
197+
<div className="space-y-3">
198+
{[
199+
"❌ No active Patreon subscription",
200+
"🔒 OAuth authorization denied",
201+
"⚠️ Account linking error",
202+
"🔌 Connection timeout",
203+
].map((cause, index) => (
204+
<div
205+
key={index}
206+
className="flex items-center gap-3 text-default-600 font-medium text-sm"
207+
style={{
208+
animation: `slideInLeft 0.5s ease-out ${index * 0.1}s both`,
209+
}}
210+
>
211+
<span className="text-lg">{cause.split(" ")[0]}</span>
212+
<span>{cause.split(" ").slice(1).join(" ")}</span>
213+
</div>
214+
))}
215+
</div>
216+
</div>
217+
218+
{/* Action Buttons */}
219+
<div className="flex flex-col gap-3">
220+
<Button
221+
size="lg"
222+
className="w-full font-semibold bg-gradient-to-r from-red-500 to-orange-600 hover:from-red-600 hover:to-orange-700 text-white"
223+
onPress={handleTryAgain}
224+
>
225+
Try Again with Patreon
226+
</Button>
227+
<Button
228+
size="lg"
229+
variant="bordered"
230+
className="w-full font-semibold border-default-300"
231+
onPress={handleGoBack}
232+
>
233+
Back to Login
234+
</Button>
235+
</div>
236+
237+
{/* Help Section */}
238+
<div className="text-center pt-4 border-t border-default-200">
239+
<p className="text-xs text-default-500 mb-2">
240+
Need help? Contact our support team
241+
</p>
242+
<Button
243+
size="sm"
244+
variant="light"
245+
className="text-xs text-blue-600 hover:text-blue-700"
246+
onPress={() =>
247+
window.open(
248+
"https://github.com/H1B0B0/Kick-Viewerbot/issues",
249+
"_blank"
250+
)
251+
}
252+
>
253+
Report an Issue
254+
</Button>
255+
</div>
256+
</CardBody>
257+
</Card>
258+
259+
<style jsx>{`
260+
@keyframes slideInLeft {
261+
from {
262+
opacity: 0;
263+
transform: translateX(-20px);
264+
}
265+
to {
266+
opacity: 1;
267+
transform: translateX(0);
268+
}
269+
}
270+
271+
@keyframes float {
272+
0%,
273+
100% {
274+
transform: translateY(0) translateX(0);
275+
}
276+
50% {
277+
transform: translateY(-20px) translateX(10px);
278+
}
279+
}
280+
281+
.animate-float {
282+
animation: float linear infinite;
283+
}
284+
285+
@keyframes gradient-xy {
286+
0%,
287+
100% {
288+
background-position: 0% 50%;
289+
}
290+
50% {
291+
background-position: 100% 50%;
292+
}
293+
}
294+
295+
.animate-gradient-xy {
296+
background-size: 400% 400%;
297+
animation: gradient-xy 15s ease infinite;
298+
}
299+
300+
.animate-gradient-x {
301+
background-size: 200% 200%;
302+
animation: gradient-xy 3s ease infinite;
303+
}
304+
`}</style>
305+
</div>
306+
);
307+
}

0 commit comments

Comments
 (0)