Historique des concerts
-Retrouvez la setlist jouée à chaque concert précédent.
+Historique des concerts
+Du plus récent au plus ancien en défilant vers le bas.
+diff --git a/README.md b/README.md
index 82c9bab..11e2c3f 100644
--- a/README.md
+++ b/README.md
@@ -240,7 +240,7 @@ erDiagram
| `/index.html` | Tous (lecture et écriture) | Répertoire des morceaux travaillés, liens/vignettes YouTube et Spotify, tutos embarqués par morceau et par instrument. Ajout avec autocomplete titre/artiste + liens auto-trouvés ([détails](#recherche-automatique-de-morceaux)) |
| `/suggestions.html` | Tous | Proposer un morceau (liens YouTube et Spotify + note libre), voter approuver/rejeter avec commentaire (attribué nominativement), ajouter une suggestion au répertoire |
| `/setlist.html` | Tous (lecture et écriture) | Setlist du prochain concert : choix des morceaux du répertoire, ordre, notes, section rappel |
-| `/history.html`, `/history-detail.html` | Tous (lecture et écriture) | Historique des setlists des concerts passés — modifiable (date, morceaux, ordre, rappel) et supprimable en cas d'erreur |
+| `/history.html`, `/history-detail.html` | Tous (lecture et écriture) | Historique des concerts passés, modifiable (date, morceaux, ordre, rappel) et supprimable. `/history.html` propose deux vues : chronologique (par défaut, tous les concerts détaillés avec YouTube embarqué par morceau, du plus récent au plus ancien) et réduite (liste compacte, comme avant) |
| `/profile.html` | Chacun voit le sien | Profil issu d'Authentik (nom, avatar, groupes) + votre activité (morceaux ajoutés, suggestions, votes) |
| `/calendar.html` | Tous (lecture et écriture) | Disponibilités du groupe pour les 3 prochaines semaines (calendrier, filtres par personne, modale par jour) — [détails](#disponibilités-calendrier) |
diff --git a/public/css/style.css b/public/css/style.css
index a0c940f..53a0875 100644
--- a/public/css/style.css
+++ b/public/css/style.css
@@ -670,6 +670,31 @@ button:disabled {
border: 0;
}
+/* ---------- History timeline ---------- */
+
+.timeline-concert { margin-bottom: 1.5rem; }
+
+.timeline-songs {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
+ gap: 0.9rem;
+ margin-top: 0.5rem;
+}
+
+.timeline-song-card {
+ background: var(--surface-alt);
+ border: 1px solid var(--border);
+ border-radius: var(--radius-sm);
+ padding: 0.7rem;
+}
+
+.timeline-song-title { font-weight: 600; }
+
+.timeline-embed {
+ max-width: none;
+ margin-top: 0.5rem;
+}
+
/* ---------- Setlist ---------- */
.setlist-columns {
diff --git a/public/history.html b/public/history.html
index f468a85..b10ae4d 100644
--- a/public/history.html
+++ b/public/history.html
@@ -12,10 +12,17 @@
Retrouvez la setlist jouée à chaque concert précédent. Du plus récent au plus ancien en défilant vers le bas.Historique des concerts
- Historique des concerts
+
Pas de lien YouTube
`} + ${song.spotify_url ? `` : ''} + ${song.note ? `${escapeHtml(song.note)}
` : ''} +Aucun morceau enregistré.
'} +Aucun concert passé enregistré.
'; + return; + } + container.innerHTML = concerts.map(timelineConcertBlock).join(''); +} + +function renderCompact() { + const container = document.getElementById('compact-view'); + renderList(container, concerts, concertCardTemplate, 'Aucun concert passé enregistré.'); +} + +function applyViewMode() { + const timelineEl = document.getElementById('timeline-view'); + const compactEl = document.getElementById('compact-view'); + const btn = document.getElementById('toggle-view-btn'); + if (viewMode === 'timeline') { + timelineEl.style.display = 'block'; + compactEl.style.display = 'none'; + btn.textContent = 'Vue réduite'; + } else { + timelineEl.style.display = 'none'; + compactEl.style.display = 'grid'; + btn.textContent = 'Vue chronologique'; + } +} + function showError(message) { document.getElementById('error').innerHTML = ``; } (async function init() { await initNav('history'); + + document.getElementById('toggle-view-btn').addEventListener('click', () => { + viewMode = viewMode === 'timeline' ? 'compact' : 'timeline'; + applyViewMode(); + }); + try { - const history = await api.get('/api/setlists/history'); - renderList(document.getElementById('history-list'), history, concertTemplate, 'Aucun concert passé enregistré.'); + concerts = await api.get('/api/setlists/history?full=1'); + renderTimeline(); + renderCompact(); + applyViewMode(); } catch (err) { showError(err.message); } diff --git a/src/repositories/setlistsRepo.js b/src/repositories/setlistsRepo.js index 23ec04f..be1bd35 100644 --- a/src/repositories/setlistsRepo.js +++ b/src/repositories/setlistsRepo.js @@ -21,6 +21,31 @@ async function findHistory() { return rows; } +async function findHistoryWithSongs() { + const { rows } = await pool.query( + `SELECT sl.id, sl.name, sl.venue, sl.concert_date, sl.created_by, sl.created_at, sl.updated_at, + COALESCE( + ( + SELECT json_agg( + json_build_object( + 'id', ss.id, 'song_id', ss.song_id, 'title', s.title, 'artist', s.artist, + 'youtube_url', s.youtube_url, 'spotify_url', s.spotify_url, + 'position', ss.position, 'note', ss.note, 'is_encore', ss.is_encore + ) + ORDER BY ss.is_encore, ss.position + ) + FROM setlist_songs ss + JOIN songs s ON s.id = ss.song_id + WHERE ss.setlist_id = sl.id + ), '[]' + ) AS songs + FROM setlists sl + WHERE sl.concert_date < CURRENT_DATE + ORDER BY sl.concert_date DESC` + ); + return rows; +} + async function findById(id) { const { rows } = await pool.query( `SELECT id, name, venue, concert_date, created_by, created_at, updated_at @@ -107,6 +132,7 @@ async function removeSong(setlistId, setlistSongId) { module.exports = { findNext, findHistory, + findHistoryWithSongs, findById, findSongs, create, diff --git a/src/routes/setlists.js b/src/routes/setlists.js index 8a15b72..4ddf19f 100644 --- a/src/routes/setlists.js +++ b/src/routes/setlists.js @@ -21,6 +21,9 @@ router.get( router.get( '/history', asyncHandler(async (req, res) => { + if (req.query.full) { + return res.json(await setlistsRepo.findHistoryWithSongs()); + } res.json(await setlistsRepo.findHistory()); }) );