changemaker.lite/api/src/modules/social/achievements.routes.ts

100 lines
3.2 KiB
TypeScript

import { Router } from 'express';
import { authenticate } from '../../middleware/auth.middleware';
import { checkSocialEnabled } from './social.middleware';
import { achievementsService } from './achievements.service';
const router = Router();
router.use(authenticate, checkSocialEnabled);
/** GET /api/social/achievements — my achievements with progress */
router.get('/', async (req, res, next) => {
try {
const achievements = await achievementsService.listForUser(req.user!.id);
res.json({ achievements });
} catch (err) {
next(err);
}
});
/** GET /api/social/achievements/definitions — all achievement definitions */
router.get('/definitions', async (_req, res) => {
res.json({ achievements: achievementsService.getDefinitions() });
});
/** GET /api/social/achievements/stats — my volunteer stats */
router.get('/stats', async (req, res, next) => {
try {
const stats = await achievementsService.getVolunteerStats(req.user!.id);
res.json({ stats });
} catch (err) {
next(err);
}
});
/** GET /api/social/achievements/stats/:userId — another user's stats (privacy-filtered) */
router.get('/stats/:userId', async (req, res, next) => {
try {
const targetUserId = req.params.userId as string;
// Privacy check
const privacy = await (await import('../../config/database')).prisma.privacySettings.findUnique({
where: { userId: targetUserId },
});
if (privacy?.showInFriendActivity === false && targetUserId !== req.user!.id) {
return res.json({ stats: null });
}
const stats = await achievementsService.getVolunteerStats(targetUserId);
res.json({ stats });
} catch (err) {
next(err);
}
});
/** GET /api/social/achievements/user/:userId — another user's achievements */
router.get('/user/:userId', async (req, res, next) => {
try {
const targetUserId = req.params.userId as string;
// Privacy check
const privacy = await (await import('../../config/database')).prisma.privacySettings.findUnique({
where: { userId: targetUserId },
});
if (privacy?.showInFriendActivity === false && targetUserId !== req.user!.id) {
return res.json({ achievements: [] });
}
const achievements = await achievementsService.listForUser(targetUserId);
// Only return unlocked achievements for other users
const filtered = targetUserId === req.user!.id
? achievements
: achievements.filter((a) => a.unlocked);
res.json({ achievements: filtered });
} catch (err) {
next(err);
}
});
/** GET /api/social/achievements/leaderboard — leaderboard */
router.get('/leaderboard', async (req, res, next) => {
try {
const type = (req.query.type as string) || 'canvass';
if (!['canvass', 'shifts', 'campaigns'].includes(type)) {
return res.status(400).json({ error: { message: 'Invalid leaderboard type' } });
}
const limit = Math.min(parseInt(req.query.limit as string) || 10, 50);
const leaderboard = await achievementsService.getLeaderboard(type as 'canvass' | 'shifts' | 'campaigns', limit);
const myRank = await achievementsService.getUserRank(req.user!.id, type as 'canvass' | 'shifts' | 'campaigns');
res.json({ leaderboard, myRank, type });
} catch (err) {
next(err);
}
});
export const achievementsRouter = router;