This commit adds a complete gamification system with analytics dashboards, leaderboards, and enhanced badge tracking functionality. Backend Features: - Analytics API with overview, user stats, activity trends, top contributors, and street statistics endpoints - Leaderboard API supporting global, weekly, monthly, and friends views - Profile API for viewing and managing user profiles - Enhanced gamification service with badge progress tracking and user stats - Comprehensive test coverage for analytics and leaderboard endpoints - Profile validation middleware for secure profile updates Frontend Features: - Analytics dashboard with multiple tabs (Overview, Activity, Personal Stats) - Interactive charts for activity trends and street statistics - Leaderboard component with pagination and timeframe filtering - Badge collection display with progress tracking - Personal stats component showing user achievements - Contributors list for top performing users - Profile management components (View/Edit) - Toast notifications integrated throughout - Comprehensive test coverage for Leaderboard component Enhancements: - User model enhanced with stats tracking and badge management - Fixed express.Router() capitalization bug in users route - Badge service improvements for better criteria matching - Removed unused imports in Profile component This feature enables users to track their contributions, view community analytics, compete on leaderboards, and earn badges for achievements. 🤖 Generated with OpenCode Co-Authored-By: AI Assistant <noreply@opencode.ai>
88 lines
2.1 KiB
JavaScript
88 lines
2.1 KiB
JavaScript
const express = require("express");
|
|
const Badge = require("../models/Badge");
|
|
const UserBadge = require("../models/UserBadge");
|
|
const auth = require("../middleware/auth");
|
|
const { asyncHandler } = require("../middleware/errorHandler");
|
|
const { getUserBadgeProgress } = require("../services/gamificationService");
|
|
const { getCacheMiddleware } = require("../middleware/cache");
|
|
|
|
const router = express.Router();
|
|
|
|
/**
|
|
* GET /api/badges
|
|
* Get all available badges
|
|
*/
|
|
router.get(
|
|
"/",
|
|
getCacheMiddleware(600), // 10 minute cache
|
|
asyncHandler(async (req, res) => {
|
|
const badges = await Badge.findAll();
|
|
// Sort by order and rarity in JavaScript since CouchDB doesn't support complex sorting
|
|
badges.sort((a, b) => {
|
|
if (a.order !== b.order) return a.order - b.order;
|
|
return a.rarity.localeCompare(b.rarity);
|
|
});
|
|
res.json(badges);
|
|
})
|
|
);
|
|
|
|
/**
|
|
* GET /api/badges/progress
|
|
* Get current user's badge progress (requires authentication)
|
|
*/
|
|
router.get(
|
|
"/progress",
|
|
auth,
|
|
getCacheMiddleware(600), // 10 minute cache
|
|
asyncHandler(async (req, res) => {
|
|
const progress = await getUserBadgeProgress(req.user.id);
|
|
res.json(progress);
|
|
})
|
|
);
|
|
|
|
/**
|
|
* GET /api/users/:userId/badges
|
|
* Get badges earned by a specific user with progress
|
|
*/
|
|
router.get(
|
|
"/users/:userId",
|
|
getCacheMiddleware(600), // 10 minute cache
|
|
asyncHandler(async (req, res) => {
|
|
const { userId } = req.params;
|
|
|
|
const userBadges = await UserBadge.findByUser(userId);
|
|
|
|
// Sort by earnedAt in JavaScript
|
|
userBadges.sort((a, b) => new Date(b.earnedAt) - new Date(a.earnedAt));
|
|
|
|
res.json(
|
|
userBadges.map((ub) => ({
|
|
badge: ub.badge,
|
|
earnedAt: ub.earnedAt,
|
|
progress: ub.progress,
|
|
}))
|
|
);
|
|
})
|
|
);
|
|
|
|
/**
|
|
* GET /api/badges/:badgeId
|
|
* Get a specific badge by ID
|
|
*/
|
|
router.get(
|
|
"/:badgeId",
|
|
getCacheMiddleware(600), // 10 minute cache
|
|
asyncHandler(async (req, res) => {
|
|
const { badgeId } = req.params;
|
|
|
|
const badge = await Badge.findById(badgeId);
|
|
if (!badge) {
|
|
return res.status(404).json({ msg: "Badge not found" });
|
|
}
|
|
|
|
res.json(badge);
|
|
})
|
|
);
|
|
|
|
module.exports = router;
|