Add summary statistics endpoint and UI integration
- Introduced a new API endpoint `GET /stats/summary` to retrieve detailed smoking statistics for users, including daily and global averages. - Updated the API client to support fetching summary statistics. - Enhanced the statistics page with a new tab for summary statistics, featuring key metrics and visualizations for user comparison. - Implemented error handling and loading states for the summary statistics fetch operation. - Refactored the statistics page to separate daily and summary statistics into distinct components for improved organization and readability.
This commit is contained in:
@@ -5,9 +5,16 @@ const timer = (time = 300) => (req, res, next) => setTimeout(next, time);
|
||||
router.use(timer());
|
||||
|
||||
// In-memory storage for demo
|
||||
const users = [];
|
||||
const users = [
|
||||
{
|
||||
id: '1',
|
||||
login: 'testuser',
|
||||
password: 'test1234',
|
||||
created: new Date('2024-01-01T00:00:00.000Z').toISOString()
|
||||
}
|
||||
];
|
||||
const cigarettes = [];
|
||||
let userIdCounter = 1;
|
||||
let userIdCounter = 2;
|
||||
let cigaretteIdCounter = 1;
|
||||
|
||||
// Simple token generation (for demo purposes only)
|
||||
@@ -191,4 +198,108 @@ router.get('/stats/daily', authMiddleware, (req, res) => {
|
||||
});
|
||||
});
|
||||
|
||||
// GET /stats/summary
|
||||
router.get('/stats/summary', authMiddleware, (req, res) => {
|
||||
const { from, to } = req.query;
|
||||
|
||||
// Default: 30 days ago to now
|
||||
const fromDate = from ? new Date(from) : new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
|
||||
const toDate = to ? new Date(to) : new Date();
|
||||
|
||||
// Helper function to get day name in Russian
|
||||
const getDayName = (dayOfWeek) => {
|
||||
const names = ['', 'Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'];
|
||||
return names[dayOfWeek];
|
||||
};
|
||||
|
||||
// Helper function to calculate stats for a set of cigarettes
|
||||
const calculateStats = (cigs) => {
|
||||
// Daily stats
|
||||
const dailyStats = {};
|
||||
cigs.forEach(c => {
|
||||
const date = c.smokedAt.split('T')[0];
|
||||
dailyStats[date] = (dailyStats[date] || 0) + 1;
|
||||
});
|
||||
|
||||
const daily = Object.entries(dailyStats)
|
||||
.map(([date, count]) => ({ date, count }))
|
||||
.sort((a, b) => a.date.localeCompare(b.date));
|
||||
|
||||
// Weekday stats (1=Sunday, 2=Monday, ..., 7=Saturday)
|
||||
const weekdayStats = {};
|
||||
cigs.forEach(c => {
|
||||
const date = new Date(c.smokedAt);
|
||||
const dayOfWeek = date.getDay() + 1; // JS getDay() returns 0-6, we want 1-7
|
||||
weekdayStats[dayOfWeek] = (weekdayStats[dayOfWeek] || 0) + 1;
|
||||
});
|
||||
|
||||
// Count occurrences of each weekday in the period
|
||||
const weekdayCounts = {};
|
||||
let current = new Date(fromDate);
|
||||
while (current <= toDate) {
|
||||
const dayOfWeek = current.getDay() + 1;
|
||||
weekdayCounts[dayOfWeek] = (weekdayCounts[dayOfWeek] || 0) + 1;
|
||||
current.setDate(current.getDate() + 1);
|
||||
}
|
||||
|
||||
const weekday = Object.entries(weekdayStats)
|
||||
.map(([dayOfWeek, count]) => {
|
||||
const dow = parseInt(dayOfWeek);
|
||||
const occurrences = weekdayCounts[dow] || 1;
|
||||
return {
|
||||
dayOfWeek: dow,
|
||||
dayName: getDayName(dow),
|
||||
count,
|
||||
average: (count / occurrences).toFixed(2)
|
||||
};
|
||||
})
|
||||
.sort((a, b) => a.dayOfWeek - b.dayOfWeek);
|
||||
|
||||
const total = cigs.length;
|
||||
const daysWithData = Object.keys(dailyStats).length;
|
||||
const averagePerDay = daysWithData > 0 ? total / daysWithData : 0;
|
||||
|
||||
return {
|
||||
daily,
|
||||
averagePerDay: parseFloat(averagePerDay.toFixed(2)),
|
||||
weekday,
|
||||
total,
|
||||
daysWithData
|
||||
};
|
||||
};
|
||||
|
||||
// User cigarettes
|
||||
const userCigarettes = cigarettes.filter(c => {
|
||||
if (c.userId !== req.userId) return false;
|
||||
const smokedDate = new Date(c.smokedAt);
|
||||
return smokedDate >= fromDate && smokedDate <= toDate;
|
||||
});
|
||||
|
||||
// Global cigarettes (all users)
|
||||
const globalCigarettes = cigarettes.filter(c => {
|
||||
const smokedDate = new Date(c.smokedAt);
|
||||
return smokedDate >= fromDate && smokedDate <= toDate;
|
||||
});
|
||||
|
||||
// Count active users
|
||||
const activeUsers = new Set(globalCigarettes.map(c => c.userId)).size;
|
||||
|
||||
// Calculate stats
|
||||
const userStats = calculateStats(userCigarettes);
|
||||
const globalStats = calculateStats(globalCigarettes);
|
||||
globalStats.activeUsers = activeUsers;
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
body: {
|
||||
user: userStats,
|
||||
global: globalStats,
|
||||
period: {
|
||||
from: fromDate.toISOString(),
|
||||
to: toDate.toISOString()
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
Reference in New Issue
Block a user