2026-07-09 18:38:22 +02:00
|
|
|
let allSongs = [];
|
2026-07-08 16:04:22 +02:00
|
|
|
let concerts = [];
|
2026-07-09 18:38:22 +02:00
|
|
|
let historyViewMode = 'timeline';
|
2026-07-08 16:04:22 +02:00
|
|
|
|
2026-07-08 11:05:21 +02:00
|
|
|
function formatDate(dateStr) {
|
2026-07-08 16:04:22 +02:00
|
|
|
const d = new Date(dateStr);
|
|
|
|
|
return d.toLocaleDateString('fr-FR', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function formatDateShort(dateStr) {
|
2026-07-08 11:05:21 +02:00
|
|
|
const d = new Date(dateStr);
|
|
|
|
|
return d.toLocaleDateString('fr-FR', { year: 'numeric', month: 'long', day: 'numeric' });
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-09 18:38:22 +02:00
|
|
|
function showError(message) {
|
|
|
|
|
document.getElementById('error').innerHTML = `<div class="error-banner">${escapeHtml(message)}</div>`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------- Tabs ----------
|
|
|
|
|
|
|
|
|
|
function switchTab(tab) {
|
|
|
|
|
document.getElementById('next-view').style.display = tab === 'next' ? '' : 'none';
|
|
|
|
|
document.getElementById('history-view').style.display = tab === 'history' ? '' : 'none';
|
|
|
|
|
document.getElementById('tab-next').classList.toggle('active', tab === 'next');
|
|
|
|
|
document.getElementById('tab-history').classList.toggle('active', tab === 'history');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------- Historique: liste (timeline / compact) ----------
|
|
|
|
|
|
2026-07-08 16:16:51 +02:00
|
|
|
function timelineSongRow(song) {
|
2026-07-08 16:04:22 +02:00
|
|
|
const embed = youtubeEmbedUrl(song.youtube_url);
|
|
|
|
|
return `
|
2026-07-08 16:16:51 +02:00
|
|
|
<div class="timeline-song-row">
|
|
|
|
|
<div class="row-index">${song.position}</div>
|
|
|
|
|
<div class="timeline-song-main">
|
|
|
|
|
<div class="timeline-song-title">${escapeHtml(song.title)}</div>
|
|
|
|
|
<div class="card-subtitle">${escapeHtml(song.artist)}</div>
|
|
|
|
|
${song.note ? `<p class="note">${escapeHtml(song.note)}</p>` : ''}
|
|
|
|
|
${song.spotify_url ? `<div class="song-links"><a class="pill-link spotify" href="${escapeHtml(song.spotify_url)}" target="_blank" rel="noopener">♫ Spotify</a></div>` : ''}
|
|
|
|
|
</div>
|
2026-07-08 16:04:22 +02:00
|
|
|
${embed
|
|
|
|
|
? `<div class="youtube-embed timeline-embed"><iframe src="${embed}" loading="lazy" allowfullscreen></iframe></div>`
|
2026-07-08 16:16:51 +02:00
|
|
|
: `<p class="empty timeline-no-embed">Pas de lien YouTube</p>`}
|
2026-07-08 16:04:22 +02:00
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function timelineConcertBlock(concert) {
|
|
|
|
|
const main = concert.songs.filter((s) => !s.is_encore);
|
|
|
|
|
const encore = concert.songs.filter((s) => s.is_encore);
|
2026-07-08 17:20:40 +02:00
|
|
|
const playlistUrl = youtubePlaylistUrl(concert.songs.map((s) => s.youtube_url).filter(Boolean));
|
2026-07-08 16:04:22 +02:00
|
|
|
return `
|
|
|
|
|
<div class="card timeline-concert">
|
|
|
|
|
<div class="card-title">${escapeHtml(concert.name || 'Concert')}</div>
|
|
|
|
|
<div class="card-subtitle">${escapeHtml(concert.venue || '')} · ${formatDate(concert.concert_date)}</div>
|
2026-07-08 17:20:40 +02:00
|
|
|
${playlistUrl ? `<div class="song-links"><a class="pill-link youtube" href="${playlistUrl}" target="_blank" rel="noopener">► Écouter la setlist sur YouTube</a></div>` : ''}
|
2026-07-08 16:04:22 +02:00
|
|
|
|
|
|
|
|
<div class="setlist-section">
|
|
|
|
|
<h3>Setlist</h3>
|
|
|
|
|
${main.length
|
2026-07-08 16:16:51 +02:00
|
|
|
? `<div class="timeline-songs">${main.map(timelineSongRow).join('')}</div>`
|
2026-07-08 16:04:22 +02:00
|
|
|
: '<p class="empty">Aucun morceau enregistré.</p>'}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
${encore.length ? `
|
|
|
|
|
<div class="setlist-section">
|
|
|
|
|
<h3>Rappel</h3>
|
2026-07-08 16:16:51 +02:00
|
|
|
<div class="timeline-songs">${encore.map(timelineSongRow).join('')}</div>
|
2026-07-08 16:04:22 +02:00
|
|
|
</div>` : ''}
|
|
|
|
|
|
2026-07-09 18:38:22 +02:00
|
|
|
<a class="back-link" href="#" data-concert-id="${concert.id}">Voir / modifier ce concert →</a>
|
2026-07-08 16:04:22 +02:00
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function concertCardTemplate(c) {
|
2026-07-08 11:05:21 +02:00
|
|
|
return `
|
|
|
|
|
<div class="card">
|
2026-07-09 18:38:22 +02:00
|
|
|
<a href="#" data-concert-id="${c.id}" style="text-decoration:none;color:inherit">
|
2026-07-08 11:05:21 +02:00
|
|
|
<div class="card-title">${escapeHtml(c.name || 'Concert')}</div>
|
2026-07-08 16:04:22 +02:00
|
|
|
<div class="card-subtitle">${escapeHtml(c.venue || '')} · ${formatDateShort(c.concert_date)}</div>
|
2026-07-08 11:05:21 +02:00
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
`;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-09 18:38:22 +02:00
|
|
|
function bindConcertLinks(container) {
|
|
|
|
|
container.querySelectorAll('[data-concert-id]').forEach((el) => {
|
|
|
|
|
el.addEventListener('click', (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
showHistoryDetail(el.dataset.concertId);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-08 16:04:22 +02:00
|
|
|
function renderTimeline() {
|
|
|
|
|
const container = document.getElementById('timeline-view');
|
|
|
|
|
if (!concerts.length) {
|
|
|
|
|
container.innerHTML = '<p class="empty">Aucun concert passé enregistré.</p>';
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
container.innerHTML = concerts.map(timelineConcertBlock).join('');
|
2026-07-09 18:38:22 +02:00
|
|
|
bindConcertLinks(container);
|
2026-07-08 16:04:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function renderCompact() {
|
|
|
|
|
const container = document.getElementById('compact-view');
|
|
|
|
|
renderList(container, concerts, concertCardTemplate, 'Aucun concert passé enregistré.');
|
2026-07-09 18:38:22 +02:00
|
|
|
bindConcertLinks(container);
|
2026-07-08 16:04:22 +02:00
|
|
|
}
|
|
|
|
|
|
2026-07-09 18:38:22 +02:00
|
|
|
function applyHistoryViewMode() {
|
2026-07-08 16:04:22 +02:00
|
|
|
const timelineEl = document.getElementById('timeline-view');
|
|
|
|
|
const compactEl = document.getElementById('compact-view');
|
2026-07-09 18:38:22 +02:00
|
|
|
const btn = document.getElementById('toggle-history-mode-btn');
|
|
|
|
|
if (historyViewMode === 'timeline') {
|
2026-07-08 16:04:22 +02:00
|
|
|
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';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-09 18:38:22 +02:00
|
|
|
async function loadHistory() {
|
|
|
|
|
concerts = await api.get('/api/setlists/history?full=1');
|
|
|
|
|
renderTimeline();
|
|
|
|
|
renderCompact();
|
|
|
|
|
applyHistoryViewMode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------- Historique: détail d'un concert ----------
|
|
|
|
|
|
|
|
|
|
function showHistoryList() {
|
|
|
|
|
document.getElementById('history-detail-view').style.display = 'none';
|
|
|
|
|
document.getElementById('history-list-view').style.display = 'block';
|
|
|
|
|
history.pushState({}, '', '/concerts.html?tab=history');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function showHistoryDetail(id) {
|
|
|
|
|
document.getElementById('history-list-view').style.display = 'none';
|
|
|
|
|
document.getElementById('history-detail-view').style.display = 'block';
|
|
|
|
|
history.pushState({}, '', `/concerts.html?tab=history&id=${id}`);
|
|
|
|
|
|
|
|
|
|
const editor = createSetlistEditor({
|
|
|
|
|
containerId: 'history-detail-content',
|
|
|
|
|
allSongs,
|
|
|
|
|
getSetlist: async () => {
|
|
|
|
|
try {
|
|
|
|
|
return await api.get(`/api/setlists/${id}`);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
emptyMessage: 'Concert introuvable.',
|
|
|
|
|
allowDelete: true,
|
|
|
|
|
onDeleted: async () => {
|
|
|
|
|
showHistoryList();
|
|
|
|
|
await loadHistory();
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
editor.load();
|
2026-07-08 11:05:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(async function init() {
|
2026-07-09 18:38:22 +02:00
|
|
|
await initNav('concerts');
|
|
|
|
|
allSongs = await api.get('/api/songs');
|
|
|
|
|
|
|
|
|
|
const nextEditor = createSetlistEditor({
|
|
|
|
|
containerId: 'next-content',
|
|
|
|
|
allSongs,
|
|
|
|
|
getSetlist: () => api.get('/api/setlists/next'),
|
|
|
|
|
createSetlist: (data) => api.post('/api/setlists', data),
|
|
|
|
|
emptyMessage: 'Aucun concert à venir pour le moment.',
|
|
|
|
|
});
|
2026-07-08 16:04:22 +02:00
|
|
|
|
2026-07-09 18:38:22 +02:00
|
|
|
document.getElementById('tab-next').addEventListener('click', () => switchTab('next'));
|
|
|
|
|
document.getElementById('tab-history').addEventListener('click', () => switchTab('history'));
|
|
|
|
|
document.getElementById('toggle-history-mode-btn').addEventListener('click', () => {
|
|
|
|
|
historyViewMode = historyViewMode === 'timeline' ? 'compact' : 'timeline';
|
|
|
|
|
applyHistoryViewMode();
|
|
|
|
|
});
|
|
|
|
|
document.getElementById('back-to-history-link').addEventListener('click', (e) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
showHistoryList();
|
2026-07-08 16:04:22 +02:00
|
|
|
});
|
|
|
|
|
|
2026-07-08 11:05:21 +02:00
|
|
|
try {
|
2026-07-09 18:38:22 +02:00
|
|
|
await nextEditor.load();
|
|
|
|
|
await loadHistory();
|
|
|
|
|
|
|
|
|
|
const params = new URLSearchParams(window.location.search);
|
|
|
|
|
const deepId = params.get('id');
|
|
|
|
|
if (deepId) {
|
|
|
|
|
switchTab('history');
|
|
|
|
|
showHistoryDetail(deepId);
|
|
|
|
|
} else if (params.get('tab') === 'history') {
|
|
|
|
|
switchTab('history');
|
|
|
|
|
}
|
2026-07-08 11:05:21 +02:00
|
|
|
} catch (err) {
|
|
|
|
|
showError(err.message);
|
|
|
|
|
}
|
|
|
|
|
})();
|