72 lines
1.9 KiB
TypeScript
72 lines
1.9 KiB
TypeScript
/**
|
|
* GET /api/leaderboard - Get top users by points
|
|
*/
|
|
|
|
import { NextRequest, NextResponse } from 'next/server';
|
|
import { getCurrentUser } from '@/app/lib/auth';
|
|
import { getAllUsers, getUserBalance, getUserCompletedTasks, getUserBadges } from '@/app/lib/db/store';
|
|
import { LeaderboardResponse, LeaderboardEntry, ApiResponse } from '@/app/lib/types';
|
|
|
|
export async function GET(request: NextRequest) {
|
|
try {
|
|
// Get current user (optional - for user rank)
|
|
const currentUser = getCurrentUser(request);
|
|
|
|
// Get all users
|
|
const users = getAllUsers();
|
|
|
|
// Build leaderboard entries
|
|
const entries: LeaderboardEntry[] = users
|
|
.map(user => ({
|
|
userId: user.id,
|
|
userName: user.name,
|
|
points: getUserBalance(user.id),
|
|
tasksCompleted: getUserCompletedTasks(user.id).length,
|
|
badgesEarned: getUserBadges(user.id).length,
|
|
rank: 0 // Will be set after sorting
|
|
}))
|
|
.sort((a, b) => {
|
|
// Sort by points descending, then by tasks completed
|
|
if (b.points !== a.points) {
|
|
return b.points - a.points;
|
|
}
|
|
return b.tasksCompleted - a.tasksCompleted;
|
|
})
|
|
.map((entry, index) => ({
|
|
...entry,
|
|
rank: index + 1
|
|
}));
|
|
|
|
// Get top 100 entries
|
|
const topEntries = entries.slice(0, 100);
|
|
|
|
// Find current user's rank
|
|
let userRank: LeaderboardEntry | undefined;
|
|
if (currentUser) {
|
|
userRank = entries.find(entry => entry.userId === currentUser.id);
|
|
}
|
|
|
|
const response: LeaderboardResponse = {
|
|
entries: topEntries,
|
|
userRank
|
|
};
|
|
|
|
return NextResponse.json<ApiResponse<LeaderboardResponse>>(
|
|
{
|
|
success: true,
|
|
data: response
|
|
},
|
|
{ status: 200 }
|
|
);
|
|
} catch (error) {
|
|
console.error('Get leaderboard error:', error);
|
|
return NextResponse.json<ApiResponse>(
|
|
{
|
|
success: false,
|
|
error: 'Internal server error'
|
|
},
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|