Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@
"typecheck": "tsc"
},
"dependencies": {
"@docusaurus/core": "3.7.0",
"@docusaurus/core": "^3.7.0",
"@docusaurus/plugin-content-docs": "3.7.0",
"@docusaurus/plugin-google-analytics": "^3.8.1",
"@docusaurus/plugin-ideal-image": "3.7.0",
"@docusaurus/preset-classic": "3.7.0",
"@docusaurus/theme-classic": "^3.8.1",
"@docusaurus/theme-mermaid": "3.7.0",
"@docusaurus/theme-search-algolia": "3.7.0",
"@floating-ui/react": "^0.27.8",
Expand All @@ -31,6 +32,7 @@
"@tsparticles/react": "^3.0.0",
"@tsparticles/slim": "^3.8.1",
"@vercel/analytics": "^1.5.0",
"canvas-confetti": "^1.9.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"dotenv": "^16.5.0",
Expand All @@ -41,7 +43,7 @@
"framer-motion": "^12.7.5",
"lucide-react": "^0.503.0",
"prism-react-renderer": "^2.3.0",
"react": "^18.0.0",
"react": "^18.3.1",
"react-dom": "^18.0.0",
"react-icons": "^5.5.0",
"react-slot-counter": "^3.3.1",
Expand All @@ -57,6 +59,7 @@
"@docusaurus/tsconfig": "3.7.0",
"@docusaurus/types": "3.7.0",
"@tailwindcss/postcss": "^4.1.4",
"@types/canvas-confetti": "^1.9.0",
"autoprefixer": "^10.4.21",
"postcss": "^8.5.3",
"tailwindcss": "^4.1.4",
Expand Down
121 changes: 121 additions & 0 deletions src/pages/dashboard/giveaway/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import React, { useEffect, useState } from 'react';
import Layout from '@theme/Layout';
import Head from '@docusaurus/Head';
import type confettiType from 'canvas-confetti';

const GiveawayPage: React.FC = () => {
const [timeLeft, setTimeLeft] = useState({
days: '--',
hours: '--',
minutes: '--',
seconds: '--',
});

const countdownTarget = new Date('2025-08-15T23:59:59').getTime(); // Update the deadline if needed

// Countdown Timer Effect
useEffect(() => {
const interval = setInterval(() => {
const now = new Date().getTime();
const distance = countdownTarget - now;

if (distance <= 0) {
clearInterval(interval);
setTimeLeft({
days: '00',
hours: '00',
minutes: '00',
seconds: '00',
});
return;
}

setTimeLeft({
days: String(Math.floor(distance / (1000 * 60 * 60 * 24))),
hours: String(Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))),
minutes: String(Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60))),
seconds: String(Math.floor((distance % (1000 * 60)) / 1000)),
});
}, 1000);

return () => clearInterval(interval);
}, []);

// Confetti Effect
useEffect(() => {
const runConfetti = async () => {
const module = await import('canvas-confetti');
const confetti = module.default as typeof confettiType;

confetti({
particleCount: 150,
spread: 70,
origin: { y: 0.6 },
});
};

const timer = setTimeout(runConfetti, 1000);

return () => clearTimeout(timer);
}, []);

return (
<Layout>
<Head>
<title>🎁 RecodeHive Giveaway</title>
</Head>

<div className="min-h-screen bg-gradient-to-br from-[#0f0c29] via-[#302b63] to-[#24243e] text-white py-10 px-6">
<div className="max-w-4xl mx-auto text-center">
<h1 className="text-4xl sm:text-5xl font-bold mb-6">🎉 RecodeHive Giveaway</h1>
<p className="text-lg mb-8">Participate now and win exclusive swag, resources, and more!</p>

<div className="flex justify-center gap-4 text-center mb-12">
{['days', 'hours', 'minutes', 'seconds'].map((unit) => (
<div key={unit} className="bg-white/10 px-6 py-4 rounded-xl shadow-md">
<div className="text-3xl font-bold">{timeLeft[unit as keyof typeof timeLeft]}</div>
<div className="text-sm uppercase tracking-widest">{unit}</div>
</div>
))}
</div>

<div className="bg-white/10 p-6 rounded-xl shadow-xl mb-10">
<h2 className="text-2xl font-semibold mb-4">🏆 Leaderboard</h2>
<table className="w-full text-left border-collapse">
<thead>
<tr className="border-b border-white/20">
<th className="pb-2">Rank</th>
<th className="pb-2">Username</th>
<th className="pb-2">Points</th>
</tr>
</thead>
<tbody>
<tr className="border-b border-white/10">
<td>1</td>
<td>OpenSourcePro</td>
<td>1200</td>
</tr>
<tr className="border-b border-white/10">
<td>2</td>
<td>CodeWizard</td>
<td>950</td>
</tr>
<tr>
<td>3</td>
<td>DevChampion</td>
<td>875</td>
</tr>
</tbody>
</table>
</div>

<p className="text-sm text-white text-opacity-60 italic">
Winners will be announced after the countdown ends. Stay active on the dashboard to climb up the leaderboard!
</p>
</div>
</div>
</Layout>
);
};

export default GiveawayPage;
80 changes: 75 additions & 5 deletions src/pages/dashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const parseCSVToJSON = (csvText: string): any[] => {
const DashboardContent: React.FC = () => {
const location = useLocation();
const history = useHistory();
const [activeTab, setActiveTab] = useState<'home' | 'discuss' | 'leaderboard'>('home');
const [activeTab, setActiveTab] = useState<'home' | 'discuss' | 'leaderboard'|'giveaway'>('home');
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);
const [leaderboardData, setLeaderboardData] = useState<LeaderboardEntry[]>([]);
const [isLoadingLeaderboard, setIsLoadingLeaderboard] = useState(false);
Expand All @@ -78,7 +78,10 @@ const DashboardContent: React.FC = () => {
setActiveTab('discuss');
} else if (location.hash === '#leaderboard') {
setActiveTab('leaderboard');
} else {
} else if (location.hash === '#giveaway'){
setActiveTab('giveaway');
}
else {
setActiveTab('home');
}
}, [location]);
Expand Down Expand Up @@ -220,15 +223,19 @@ const DashboardContent: React.FC = () => {
return achievements.slice(0, 3); // Limit to 3 achievements for UI
};

const handleTabChange = (tab: 'home' | 'discuss' | 'leaderboard') => {
const handleTabChange = (tab: 'home' | 'discuss' | 'leaderboard' | 'giveaway') => {
setActiveTab(tab);
if (tab === 'discuss') {
history.push('#discuss');
window.scrollTo(0, 0);
} else if (tab === 'leaderboard') {
history.push('#leaderboard');
window.scrollTo(0, 0);
} else {
} else if (tab === 'giveaway'){
history.push('/dashboard/giveaway');
window.scrollTo(0 , 0);
}
else {
history.push('#');
}
};
Expand Down Expand Up @@ -440,6 +447,16 @@ const DashboardContent: React.FC = () => {
<span className="nav-icon">🏆</span>
<span className="nav-text">Leaderboard</span>
</li>

<li
className={`nav-item ${activeTab === 'giveaway' ? 'active' : ''}`}
onClick={() => handleTabChange
('giveaway')}
>
<span className="nav-icon">🎁</span>
<span className="nav-text">Giveaway</span>
</li>

</ul>
<div className="sidebar-footer">
<button
Expand Down Expand Up @@ -594,7 +611,7 @@ const DashboardContent: React.FC = () => {
/>
</div>
</div>
) : (
) : activeTab === 'leaderboard' ? (
/* Leaderboard Tab */
<div className="leaderboard-page-container">
<motion.div
Expand Down Expand Up @@ -775,6 +792,59 @@ const DashboardContent: React.FC = () => {
</motion.div>
)}
</div>
) : activeTab === 'giveaway' && (
// ✅ Giveaway Section 🎁
<>
<motion.section className="dashboard-hero" initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.8 }}>
<div className="hero-content">
<h1 className="dashboard-title">
🎁 <span className="highlight">Giveaway</span>
</h1>
<p className="dashboard-subtitle">Participate in exclusive giveaways and win exciting prizes!</p>
</div>
</motion.section>

{/* 🎉 Giveaway Stats Grid */}
<motion.section
className="dashboard-stats-section"
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1 }}
transition={{ duration: 0.6 }}
viewport={{ once: true }}
>
<div className="dashboard-stats-grid">
<StatCard
icon="⏳"
title="Next Giveaway"
value="5 Days"
valueText="5 Days Left"
description="Time remaining"
/>
<StatCard
icon="🎫"
title="Entries"
value="1420"
valueText="1,420"
description="Total participants"
/>
<StatCard
icon="📈"
title="Your Rank"
value="32"
valueText="Rank 32"
description="Based on your contribution"
/>
<StatCard
icon="🏅"
title="Total Winners"
value="10"
valueText="10 Winners"
description="Winners per giveaway"
/>
</div>
</motion.section>
</>

)}
</main>
</div>
Expand Down
3 changes: 3 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
"compilerOptions": {
"jsx": "react",
"baseUrl": ".",
"esModuleInterop": true,
"moduleResolution": "node",
"resolveJsonModule": true

},
"exclude": [".docusaurus", "build"]
Expand Down
Loading