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
52 changes: 52 additions & 0 deletions src/app/api/stats/hero/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { NextResponse } from 'next/server';
import dbConnect from '@/lib/db';
import User from '@/lib/models/userSchema';
import SkillList from '@/lib/models/skillList';
import SkillMatch from '@/lib/models/skillMatch';
import { Feedback } from '@/lib/models/feedbackSchema';

export const dynamic = 'force-dynamic';

export async function GET() {
try {
await dbConnect();

// Active learners
const activeLearners = await User.countDocuments({ isDeleted: { $ne: true }, isBlocked: { $ne: true } });

// Skills available (unique skill names across all categories)
const skillLists = await SkillList.find({}).select('skills');
const skillSet = new Set();
skillLists.forEach(list => {
list.skills.forEach(skill => {
skillSet.add(skill.name);
});
});
const skillsAvailable = skillSet.size;

// Successful matches and total matches
const successfulMatches = await SkillMatch.countDocuments({ status: 'completed' });
const totalMatches = await SkillMatch.countDocuments({});

// Satisfaction rate (average rating)
const feedbacks = await Feedback.find({ rating: { $exists: true } }).select('rating');
let satisfactionRate = 0;
if (feedbacks.length > 0) {
const avg = feedbacks.reduce((sum, f) => sum + (f.rating || 0), 0) / feedbacks.length;
satisfactionRate = Math.round(avg * 20); // Convert 1-5 to %
}

return NextResponse.json({
success: true,
data: {
activeLearners,
skillsAvailable,
successfulMatches,
totalMatches,
satisfactionRate
}
});
} catch (error) {
return NextResponse.json({ success: false, message: 'Failed to fetch hero stats' }, { status: 500 });
}
}
66 changes: 59 additions & 7 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,24 @@ const EnhancedHeroSection = () => {
const router = useRouter();
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
const [isVisible, setIsVisible] = useState(false);
const [stats, setStats] = useState<{
activeLearners: number | null;
skillsAvailable: number | null;
successfulMatches: number | null;
totalMatches: number | null;
satisfactionRate: number | null;
}>({
activeLearners: null,
skillsAvailable: null,
successfulMatches: null,
totalMatches: null,
satisfactionRate: null,
});
const [loadingStats, setLoadingStats] = useState(true);

useEffect(() => {
setIsVisible(true);

const handleMouseMove = (e: MouseEvent) => {
setMousePosition({
x: (e.clientX / window.innerWidth) * 100,
Expand All @@ -40,6 +54,25 @@ const EnhancedHeroSection = () => {
return () => window.removeEventListener('mousemove', handleMouseMove);
}, []);

useEffect(() => {
// Fetch hero stats from backend
const fetchStats = async () => {
try {
setLoadingStats(true);
const res = await fetch('/api/stats/hero');
const data = await res.json();
if (data.success && data.data) {
setStats(data.data);
}
} catch (err) {
// Optionally handle error
} finally {
setLoadingStats(false);
}
};
fetchStats();
}, []);

return (
<section className="relative min-h-screen flex items-center justify-center overflow-hidden bg-gradient-to-br from-[#006699] via-blue-700 to-indigo-900">
{/* Animated Background Elements */}
Expand Down Expand Up @@ -144,13 +177,32 @@ const EnhancedHeroSection = () => {
{/* Stats */}
<div className={`grid grid-cols-2 md:grid-cols-4 gap-8 transform transition-all duration-1000 delay-800 ${isVisible ? 'translate-y-0 opacity-100' : 'translate-y-10 opacity-0'}`}>
{[
{ number: '50K+', label: 'Active Learners', icon: Users },
{ number: '1000+', label: 'Skills Available', icon: BookOpen },
{ number: '25K+', label: 'Successful Matches', icon: Star },
{ number: '95%', label: 'Satisfaction Rate', icon: Award }
{
number: loadingStats || stats.activeLearners === null ? '...' : stats.activeLearners.toLocaleString(),
label: 'Active Learners',
icon: Users
},
{
number: loadingStats || stats.skillsAvailable === null ? '...' : stats.skillsAvailable.toLocaleString(),
label: 'Skills Available',
icon: BookOpen
},
{
number:
loadingStats || stats.totalMatches === null
? '...'
: stats.totalMatches.toLocaleString(),
label: 'Total Matches',
icon: Star
},
{
number: loadingStats || stats.satisfactionRate === null ? '...' : `${stats.satisfactionRate}%`,
label: 'Satisfaction Rate',
icon: Award
}
].map((stat, index) => (
<div
key={stat.label}
<div
key={stat.label}
className="text-center group"
style={{ animationDelay: `${index * 100}ms` }}
>
Expand Down
Loading