function formatDate(dateStr) {
const d = new Date(dateStr);
return d.toLocaleDateString('fr-FR', { year: 'numeric', month: 'long', day: 'numeric' });
}
function showError(message) {
document.getElementById('error').innerHTML = `
${escapeHtml(message)}
`;
}
function statTile(value, label) {
return `
${value}
${escapeHtml(label)}
`;
}
function adminUserRowTemplate(u) {
return `
${avatarHtml(u, 'avatar-sm')}
${escapeHtml(u.name)}${u.isAdmin ? ' admin' : ''}
Membre depuis ${formatDate(u.createdAt)} · Dernière connexion ${formatDate(u.lastSeenAt)}
🎵 ${u.songsAdded}
💡 ${u.suggestionsProposed}
✔ ${u.votesCast}
`;
}
(async function init() {
const me = await initNav('admin');
if (!me.isAdmin) {
window.location.href = '/index.html';
return;
}
try {
const stats = await api.get('/api/admin/stats');
const container = document.getElementById('content');
container.innerHTML = `
Administration
Vue d'ensemble de l'activité et des données de l'application.
Vue d'ensemble
${statTile(stats.userCount, 'Utilisateurs')}
${statTile(stats.songs.totalSongs, 'Morceaux au répertoire')}
${statTile(stats.songs.distinctArtists, 'Artistes différents')}
${statTile(stats.songs.tutorialsAdded, 'Tutoriels ajoutés')}
${statTile(stats.suggestions.pending, 'Suggestions en attente')}
${statTile(stats.suggestions.approved, 'Suggestions approuvées')}
${statTile(stats.suggestions.totalVotes, 'Votes exprimés')}
${statTile(stats.concerts.pastConcerts, 'Concerts passés')}
${statTile(stats.concerts.upcomingConcerts, 'Concerts à venir')}
${statTile(stats.concerts.avgSongsPerConcert, 'Morceaux / concert (moy.)')}
Activité des utilisateurs
La date de dernière connexion est approximative (dernière synchronisation du profil, pas un journal de connexion précis).
${stats.users.map(adminUserRowTemplate).join('')}
`;
} catch (err) {
showError(err.message);
}
})();