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)}
`; } // Shown for a registered feed instead of its full URL, consistent with the // admin calendar-management panel — the URL itself is a secret (whoever has // it can read that person's calendar), so the list view doesn't re-display // the plaintext on every load. function maskIcsUrl(url) { try { const u = new URL(url); return `${u.hostname}/••••`; } catch { return '••••'; } } function myFeedRowTemplate(feed) { return `
${feed.label ? `${escapeHtml(feed.label)} — ` : ''}${escapeHtml(maskIcsUrl(feed.icsUrl))}
`; } async function loadMyFeeds() { const feeds = await api.get('/api/calendar/my-feeds'); const container = document.getElementById('my-feeds-list'); container.innerHTML = feeds.length ? feeds.map(myFeedRowTemplate).join('') : '

Aucun calendrier configuré.

'; container.querySelectorAll('.remove-my-feed-btn').forEach((btn) => { btn.addEventListener('click', () => onRemoveMyFeed(parseInt(btn.dataset.feedId, 10))); }); } async function onAddMyFeed(e) { e.preventDefault(); const form = e.target; const label = form.label.value.trim(); const icsUrl = form.icsUrl.value.trim(); try { await api.post('/api/calendar/my-feeds', { label, icsUrl }); form.reset(); await loadMyFeeds(); } catch (err) { showError(err.message); } } async function onRemoveMyFeed(feedId) { try { await api.del(`/api/calendar/my-feeds/${feedId}`); await loadMyFeeds(); } catch (err) { showError(err.message); } } (async function init() { await initNav(null); try { const profile = await api.get('/api/users/me/profile'); const container = document.getElementById('content'); container.innerHTML = `
${avatarHtml(profile, 'avatar-lg')}

${escapeHtml(profile.name)}${profile.isAdmin ? ' admin' : ''}

${profile.username ? `
@${escapeHtml(profile.username)}
` : ''} ${profile.email ? `
${escapeHtml(profile.email)}
` : ''}
Membre depuis ${formatDate(profile.createdAt)}
${profile.groups && profile.groups.length ? `

Groupes Authentik

${profile.groups.map((g) => `${escapeHtml(g)}`).join('')}
` : ''}

Votre activité

${statTile(profile.stats.songsAdded, 'Morceaux ajoutés')} ${statTile(profile.stats.suggestionsProposed, 'Suggestions proposées')} ${statTile(profile.stats.votesCast, 'Votes exprimés')}

Mes calendriers

Ajoutez le lien ICS (iCal) d'un ou plusieurs de vos calendriers (Google, Outlook, Apple...) pour apparaître dans les disponibilités du groupe sur la page Disponibilités. L'application ne conserve jamais le contenu de vos calendriers — seul un statut disponible/occupé par créneau est déduit et enregistré.

Chargement…

Comment trouver mon lien ICS ?

Identité gérée par Authentik — pour changer votre nom, email ou mot de passe, ${profile.authentikAccountUrl ? `rendez-vous sur votre compte Authentik.` : 'rendez-vous sur votre compte Authentik.'}

`; document.getElementById('add-my-feed-form').addEventListener('submit', onAddMyFeed); await loadMyFeeds(); } catch (err) { showError(err.message); } })();