Skip to content

Commit 5aa16f3

Browse files
committed
Add RecodeHive Giveaway Page with Countdown, Leaderboard & Confetti Animation
1 parent 290791f commit 5aa16f3

File tree

2 files changed

+182
-5
lines changed

2 files changed

+182
-5
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import React, { useEffect, useState } from 'react';
2+
import Layout from '@theme/Layout';
3+
import Head from '@docusaurus/Head';
4+
5+
const GiveawayPage = () => {
6+
const [timeLeft, setTimeLeft] = useState({
7+
days: '--',
8+
hours: '--',
9+
minutes: '--',
10+
seconds: '--',
11+
});
12+
13+
const countdownTarget = new Date('2025-08-15T23:59:59').getTime(); // Customize this date
14+
15+
useEffect(() => {
16+
const interval = setInterval(() => {
17+
const now = new Date().getTime();
18+
const distance = countdownTarget - now;
19+
20+
if (distance <= 0) {
21+
clearInterval(interval);
22+
setTimeLeft({
23+
days: '00',
24+
hours: '00',
25+
minutes: '00',
26+
seconds: '00',
27+
});
28+
return;
29+
}
30+
31+
setTimeLeft({
32+
days: String(Math.floor(distance / (1000 * 60 * 60 * 24))),
33+
hours: String(Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))),
34+
minutes: String(Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60))),
35+
seconds: String(Math.floor((distance % (1000 * 60)) / 1000)),
36+
});
37+
}, 1000);
38+
39+
// Confetti burst
40+
import('canvas-confetti').then(confetti => {
41+
confetti.default({ particleCount: 150, spread: 70, origin: { y: 0.6 } });
42+
});
43+
44+
return () => clearInterval(interval);
45+
}, []);
46+
47+
return (
48+
<Layout>
49+
<Head>
50+
<title>🎁 RecodeHive Giveaway</title>
51+
</Head>
52+
53+
<div className="min-h-screen bg-gradient-to-br from-[#0f0c29] via-[#302b63] to-[#24243e] text-white py-10 px-6">
54+
<div className="max-w-4xl mx-auto text-center">
55+
<h1 className="text-4xl sm:text-5xl font-bold mb-6">🎉 RecodeHive Giveaway</h1>
56+
<p className="text-lg mb-8">Participate now and win exclusive swag, resources, and more!</p>
57+
58+
<div className="flex justify-center gap-4 text-center mb-12">
59+
{['days', 'hours', 'minutes', 'seconds'].map(unit => (
60+
<div key={unit} className="bg-white/10 px-6 py-4 rounded-xl shadow-md">
61+
<div className="text-3xl font-bold">{timeLeft[unit]}</div>
62+
<div className="text-sm uppercase tracking-widest">{unit}</div>
63+
</div>
64+
))}
65+
</div>
66+
67+
<div className="bg-white/10 p-6 rounded-xl shadow-xl mb-10">
68+
<h2 className="text-2xl font-semibold mb-4">🏆 Leaderboard</h2>
69+
<table className="w-full text-left border-collapse">
70+
<thead>
71+
<tr className="border-b border-white/20">
72+
<th className="pb-2">Rank</th>
73+
<th className="pb-2">Username</th>
74+
<th className="pb-2">Points</th>
75+
</tr>
76+
</thead>
77+
<tbody>
78+
{/* Replace this static data with dynamic data if needed */}
79+
<tr className="border-b border-white/10">
80+
<td>1</td>
81+
<td>OpenSourcePro</td>
82+
<td>1200</td>
83+
</tr>
84+
<tr className="border-b border-white/10">
85+
<td>2</td>
86+
<td>CodeWizard</td>
87+
<td>950</td>
88+
</tr>
89+
<tr>
90+
<td>3</td>
91+
<td>DevChampion</td>
92+
<td>875</td>
93+
</tr>
94+
</tbody>
95+
</table>
96+
</div>
97+
98+
<p className="text-sm text-white/60 italic">
99+
Winners will be announced after the countdown ends. Stay active on the dashboard to climb up the leaderboard!
100+
</p>
101+
</div>
102+
</div>
103+
</Layout>
104+
);
105+
};
106+
107+
export default GiveawayPage;

src/pages/dashboard/index.tsx

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ const parseCSVToJSON = (csvText: string): any[] => {
6666
const DashboardContent: React.FC = () => {
6767
const location = useLocation();
6868
const history = useHistory();
69-
const [activeTab, setActiveTab] = useState<'home' | 'discuss' | 'leaderboard'>('home');
69+
const [activeTab, setActiveTab] = useState<'home' | 'discuss' | 'leaderboard'|'giveaway'>('home');
7070
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);
7171
const [leaderboardData, setLeaderboardData] = useState<LeaderboardEntry[]>([]);
7272
const [isLoadingLeaderboard, setIsLoadingLeaderboard] = useState(false);
@@ -78,7 +78,10 @@ const DashboardContent: React.FC = () => {
7878
setActiveTab('discuss');
7979
} else if (location.hash === '#leaderboard') {
8080
setActiveTab('leaderboard');
81-
} else {
81+
} else if (location.hash === '#giveaway'){
82+
setActiveTab('giveaway');
83+
}
84+
else {
8285
setActiveTab('home');
8386
}
8487
}, [location]);
@@ -220,15 +223,19 @@ const DashboardContent: React.FC = () => {
220223
return achievements.slice(0, 3); // Limit to 3 achievements for UI
221224
};
222225

223-
const handleTabChange = (tab: 'home' | 'discuss' | 'leaderboard') => {
226+
const handleTabChange = (tab: 'home' | 'discuss' | 'leaderboard' | 'giveaway') => {
224227
setActiveTab(tab);
225228
if (tab === 'discuss') {
226229
history.push('#discuss');
227230
window.scrollTo(0, 0);
228231
} else if (tab === 'leaderboard') {
229232
history.push('#leaderboard');
230233
window.scrollTo(0, 0);
231-
} else {
234+
} else if (tab === 'giveaway'){
235+
history.push('/dashboard/giveaway');
236+
window.scrollTo(0 , 0);
237+
}
238+
else {
232239
history.push('#');
233240
}
234241
};
@@ -440,6 +447,16 @@ const DashboardContent: React.FC = () => {
440447
<span className="nav-icon">🏆</span>
441448
<span className="nav-text">Leaderboard</span>
442449
</li>
450+
451+
<li
452+
className={`nav-item ${activeTab === 'giveaway' ? 'active' : ''}`}
453+
onClick={() => handleTabChange
454+
('giveaway')}
455+
>
456+
<span className="nav-icon">🎁</span>
457+
<span className="nav-text">Giveaway</span>
458+
</li>
459+
443460
</ul>
444461
<div className="sidebar-footer">
445462
<button
@@ -594,7 +611,7 @@ const DashboardContent: React.FC = () => {
594611
/>
595612
</div>
596613
</div>
597-
) : (
614+
) : activeTab === 'leaderboard' ? (
598615
/* Leaderboard Tab */
599616
<div className="leaderboard-page-container">
600617
<motion.div
@@ -775,6 +792,59 @@ const DashboardContent: React.FC = () => {
775792
</motion.div>
776793
)}
777794
</div>
795+
) : activeTab === 'giveaway' && (
796+
// ✅ Giveaway Section 🎁
797+
<>
798+
<motion.section className="dashboard-hero" initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.8 }}>
799+
<div className="hero-content">
800+
<h1 className="dashboard-title">
801+
🎁 <span className="highlight">Giveaway</span>
802+
</h1>
803+
<p className="dashboard-subtitle">Participate in exclusive giveaways and win exciting prizes!</p>
804+
</div>
805+
</motion.section>
806+
807+
{/* 🎉 Giveaway Stats Grid */}
808+
<motion.section
809+
className="dashboard-stats-section"
810+
initial={{ opacity: 0, y: 10 }}
811+
whileInView={{ opacity: 1 }}
812+
transition={{ duration: 0.6 }}
813+
viewport={{ once: true }}
814+
>
815+
<div className="dashboard-stats-grid">
816+
<StatCard
817+
icon="⏳"
818+
title="Next Giveaway"
819+
value="5 Days"
820+
valueText="5 Days Left"
821+
description="Time remaining"
822+
/>
823+
<StatCard
824+
icon="🎫"
825+
title="Entries"
826+
value="1420"
827+
valueText="1,420"
828+
description="Total participants"
829+
/>
830+
<StatCard
831+
icon="📈"
832+
title="Your Rank"
833+
value="32"
834+
valueText="Rank 32"
835+
description="Based on your contribution"
836+
/>
837+
<StatCard
838+
icon="🏅"
839+
title="Total Winners"
840+
value="10"
841+
valueText="10 Winners"
842+
description="Winners per giveaway"
843+
/>
844+
</div>
845+
</motion.section>
846+
</>
847+
778848
)}
779849
</main>
780850
</div>

0 commit comments

Comments
 (0)