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 = `
`; } function statTile(value, label) { return `Aucun calendrier configuré.
'}Aucun utilisateur pour le moment.
'; container.querySelectorAll('.add-feed-form').forEach((form) => { form.addEventListener('submit', (e) => onAddFeed(e, parseInt(form.dataset.userId, 10))); }); container.querySelectorAll('.remove-feed-btn').forEach((btn) => { btn.addEventListener('click', () => onRemoveFeed(parseInt(btn.dataset.feedId, 10))); }); } async function onAddFeed(e, userId) { e.preventDefault(); const form = e.target; const label = form.label.value.trim(); const icsUrl = form.icsUrl.value.trim(); try { await api.post(`/api/calendar/people/${userId}/feeds`, { label, icsUrl }); await loadCalendarUsers(); } catch (err) { showError(err.message); } } async function onRemoveFeed(feedId) { try { await api.del(`/api/calendar/feeds/${feedId}`); await loadCalendarUsers(); } catch (err) { showError(err.message); } } async function loadSlotSettingsForm() { const settings = await api.get('/api/calendar/settings'); const form = document.getElementById('slot-settings-form'); form.weekdayStart.value = settings.weekdayStart; form.weekdayEnd.value = settings.weekdayEnd; form.weekendStart.value = settings.weekendStart; form.weekendEnd.value = settings.weekendEnd; form.marginMinutes.value = settings.marginMinutes; } async function onSaveSlotSettings(e) { e.preventDefault(); const form = e.target; const statusEl = document.getElementById('slot-settings-status'); statusEl.textContent = ''; try { await api.patch('/api/calendar/settings', { weekdayStart: form.weekdayStart.value, weekdayEnd: form.weekdayEnd.value, weekendStart: form.weekendStart.value, weekendEnd: form.weekendEnd.value, marginMinutes: parseInt(form.marginMinutes.value, 10), }); statusEl.textContent = 'Horaires enregistrés.'; } catch (err) { showError(err.message); } } (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 = `Vue d'ensemble de l'activité et des données de l'application.
La date de dernière connexion est approximative (dernière synchronisation du profil, pas un journal de connexion précis).
Horaires utilisés pour calculer les disponibilités sur /calendar.html.
Chaque utilisateur de l'application peut avoir plusieurs calendriers (Google, Outlook, Apple...).
Seuls les utilisateurs avec au moins un calendrier configuré apparaissent sur /calendar.html.
L'application ne conserve jamais le contenu de ces calendriers — seul un statut disponible/occupé
par créneau est déduit et enregistré.
Comment trouver le lien ICS d'un utilisateur ?
Chargement…