Implement chain submissions API and update frontend to utilize new endpoint; enhance submissions page with feature flag for API selection, participant progress display, and improved filtering logic.
This commit is contained in:
@@ -461,4 +461,116 @@ router.get('/challenge/user/:userId/submissions', (req, res) => {
|
||||
respond(res, filtered);
|
||||
});
|
||||
|
||||
// GET /api/challenge/chain/:chainId/submissions
|
||||
router.get('/challenge/chain/:chainId/submissions', (req, res) => {
|
||||
const chains = getChains();
|
||||
const submissions = getSubmissions();
|
||||
const users = getUsers();
|
||||
|
||||
const chainId = req.params.chainId;
|
||||
const userId = req.query.userId;
|
||||
const status = req.query.status;
|
||||
const limit = parseInt(req.query.limit) || 100;
|
||||
const offset = parseInt(req.query.offset) || 0;
|
||||
|
||||
// Найти цепочку
|
||||
const chain = chains.find(c => c.id === chainId);
|
||||
if (!chain) {
|
||||
return respondError(res, 'Chain not found', 404);
|
||||
}
|
||||
|
||||
// Получить taskIds из цепочки
|
||||
const taskIds = new Set(chain.tasks.map(t => t.id));
|
||||
|
||||
// Фильтровать submissions по taskIds цепочки
|
||||
let filteredSubmissions = submissions.filter(s => {
|
||||
const taskId = typeof s.task === 'object' ? s.task.id : s.task;
|
||||
return taskIds.has(taskId);
|
||||
});
|
||||
|
||||
// Применить фильтр по userId если указан
|
||||
if (userId) {
|
||||
filteredSubmissions = filteredSubmissions.filter(s => {
|
||||
const subUserId = typeof s.user === 'object' ? s.user.id : s.user;
|
||||
return subUserId === userId;
|
||||
});
|
||||
}
|
||||
|
||||
// Применить фильтр по status если указан
|
||||
if (status) {
|
||||
filteredSubmissions = filteredSubmissions.filter(s => s.status === status);
|
||||
}
|
||||
|
||||
// Получить уникальных участников
|
||||
const participantMap = new Map();
|
||||
|
||||
filteredSubmissions.forEach(sub => {
|
||||
const subUserId = typeof sub.user === 'object' ? sub.user.id : sub.user;
|
||||
const subUserNickname = typeof sub.user === 'object' ? sub.user.nickname : '';
|
||||
|
||||
// Найти nickname если не заполнен
|
||||
let nickname = subUserNickname;
|
||||
if (!nickname) {
|
||||
const user = users.find(u => u.id === subUserId);
|
||||
nickname = user ? user.nickname : subUserId;
|
||||
}
|
||||
|
||||
if (!participantMap.has(subUserId)) {
|
||||
participantMap.set(subUserId, {
|
||||
userId: subUserId,
|
||||
nickname: nickname,
|
||||
completedTasks: new Set(),
|
||||
totalTasks: chain.tasks.length,
|
||||
});
|
||||
}
|
||||
|
||||
// Если статус accepted, добавляем taskId в completedTasks
|
||||
if (sub.status === 'accepted') {
|
||||
const taskId = typeof sub.task === 'object' ? sub.task.id : sub.task;
|
||||
participantMap.get(subUserId).completedTasks.add(taskId);
|
||||
}
|
||||
});
|
||||
|
||||
// Преобразовать в массив и рассчитать прогресс
|
||||
const participants = Array.from(participantMap.values()).map(p => ({
|
||||
userId: p.userId,
|
||||
nickname: p.nickname,
|
||||
completedTasks: p.completedTasks.size,
|
||||
totalTasks: p.totalTasks,
|
||||
progressPercent: p.totalTasks > 0
|
||||
? Math.round((p.completedTasks.size / p.totalTasks) * 100)
|
||||
: 0,
|
||||
}));
|
||||
|
||||
// Сортировать submissions по дате (новые сначала)
|
||||
filteredSubmissions.sort((a, b) =>
|
||||
new Date(b.submittedAt) - new Date(a.submittedAt)
|
||||
);
|
||||
|
||||
// Применить пагинацию
|
||||
const total = filteredSubmissions.length;
|
||||
const paginatedSubmissions = filteredSubmissions.slice(offset, offset + limit);
|
||||
|
||||
// Формируем ответ
|
||||
const response = {
|
||||
chain: {
|
||||
id: chain.id,
|
||||
name: chain.name,
|
||||
tasks: chain.tasks.map(t => ({
|
||||
id: t.id,
|
||||
title: t.title,
|
||||
})),
|
||||
},
|
||||
participants: participants,
|
||||
submissions: paginatedSubmissions,
|
||||
pagination: {
|
||||
total: total,
|
||||
limit: limit,
|
||||
offset: offset,
|
||||
},
|
||||
};
|
||||
|
||||
respond(res, response);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
Reference in New Issue
Block a user