let me = null; let allSongs = []; let setlist = null; let mainRows = []; let encoreRows = []; let addSongId = null; function formatDate(dateStr) { const d = new Date(dateStr); return d.toLocaleDateString('fr-FR', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); } function readOnlyView() { const main = setlist.songs.filter((s) => !s.is_encore); const encore = setlist.songs.filter((s) => s.is_encore); return `
${escapeHtml(setlist.name || 'Concert')}
${escapeHtml(setlist.venue || '')} · ${formatDate(setlist.concert_date)}

Setlist

${main.length ? `
    ${main.map((s) => `
  1. ${escapeHtml(s.title)} — ${escapeHtml(s.artist)}${s.note ? `${escapeHtml(s.note)}` : ''}
  2. `).join('')}
` : '

Aucun morceau pour le moment.

'}

Rappel

${encore.length ? `
    ${encore.map((s) => `
  1. ${escapeHtml(s.title)} — ${escapeHtml(s.artist)}${s.note ? `${escapeHtml(s.note)}` : ''}
  2. `).join('')}
` : '

Aucun morceau de rappel prévu.

'}
${me.isAdmin ? '' : ''} `; } function renderReadOnly() { const container = document.getElementById('content'); if (!setlist) { container.innerHTML = me.isAdmin ? `

Aucun concert à venir.

${metaFormTemplate()}` : '

Aucun concert à venir pour le moment.

'; if (me.isAdmin) attachMetaFormHandler(); return; } container.innerHTML = readOnlyView(); const editBtn = document.getElementById('edit-btn'); if (editBtn) editBtn.addEventListener('click', enterEditMode); } function metaFormTemplate() { return `

${setlist ? 'Détails du concert' : 'Créer le prochain concert'}

`; } function usedSongIds() { return new Set([...mainRows, ...encoreRows].map((r) => r.songId)); } function availableSongOptions() { const used = usedSongIds(); const available = allSongs.filter((s) => !used.has(s.id)); if (!available.length) return ''; return available.map((s) => ``).join(''); } function rowTemplate(row, index, section, total) { return `
${index + 1}
${escapeHtml(row.title)}
${escapeHtml(row.artist)}
`; } function editView() { return ` ${metaFormTemplate()} ${setlist ? `

Ajouter un morceau du répertoire

Programme principal

${mainRows.length ? mainRows.map((r, i) => rowTemplate(r, i, 'main', mainRows.length)).join('') : '

Aucun morceau. Ajoutez-en depuis le répertoire ci-dessus.

'}

Rappel

${encoreRows.length ? encoreRows.map((r, i) => rowTemplate(r, i, 'encore', encoreRows.length)).join('') : '

Aucun morceau de rappel prévu.

'}
` : ''} `; } function enterEditMode() { mainRows = setlist.songs .filter((s) => !s.is_encore) .map((s) => ({ setlistSongId: s.id, songId: s.song_id, title: s.title, artist: s.artist, note: s.note })); encoreRows = setlist.songs .filter((s) => s.is_encore) .map((s) => ({ setlistSongId: s.id, songId: s.song_id, title: s.title, artist: s.artist, note: s.note })); renderEdit(); } function renderEdit() { const container = document.getElementById('content'); container.innerHTML = editView(); attachMetaFormHandler(); attachEditHandlers(); } function attachMetaFormHandler() { const form = document.getElementById('meta-form'); if (!form) return; form.addEventListener('submit', async (e) => { e.preventDefault(); const name = form.name.value.trim(); const venue = form.venue.value.trim(); const concertDate = form.concertDate.value; try { if (setlist) { setlist = await api.patch(`/api/setlists/${setlist.id}`, { name, venue, concertDate }); setlist.songs = (await api.get(`/api/setlists/${setlist.id}`)).songs; } else { setlist = await api.post('/api/setlists', { name, venue, concertDate }); setlist.songs = []; } enterEditMode(); } catch (err) { showError(err.message); } }); } function rowsForSection(section) { return section === 'main' ? mainRows : encoreRows; } function attachEditHandlers() { const addSelect = document.getElementById('add-song-select'); const addToMain = document.getElementById('add-to-main-btn'); const addToEncore = document.getElementById('add-to-encore-btn'); if (addSelect) { if (!addSelect.value) addSongId = null; addSelect.addEventListener('change', () => { addSongId = addSelect.value ? parseInt(addSelect.value, 10) : null; }); } if (addToMain) addToMain.addEventListener('click', () => addSongToSection('main', addSelect)); if (addToEncore) addToEncore.addEventListener('click', () => addSongToSection('encore', addSelect)); document.querySelectorAll('.setlist-row').forEach((rowEl) => { const section = rowEl.dataset.section; const index = parseInt(rowEl.dataset.index, 10); const rows = rowsForSection(section); rowEl.querySelector('.row-note-input').addEventListener('change', (e) => { rows[index].note = e.target.value; }); rowEl.querySelector('.move-up')?.addEventListener('click', () => { if (index === 0) return; [rows[index - 1], rows[index]] = [rows[index], rows[index - 1]]; renderEdit(); }); rowEl.querySelector('.move-down')?.addEventListener('click', () => { if (index === rows.length - 1) return; [rows[index + 1], rows[index]] = [rows[index], rows[index + 1]]; renderEdit(); }); rowEl.querySelector('.move-section').addEventListener('click', () => { const [row] = rows.splice(index, 1); if (section === 'main') encoreRows.push(row); else mainRows.push(row); renderEdit(); }); rowEl.querySelector('.remove-row').addEventListener('click', () => { rows.splice(index, 1); renderEdit(); }); }); const saveBtn = document.getElementById('save-songs-btn'); if (saveBtn) saveBtn.addEventListener('click', onSaveSongs); const cancelBtn = document.getElementById('cancel-edit-btn'); if (cancelBtn) cancelBtn.addEventListener('click', renderReadOnly); } function addSongToSection(section, selectEl) { const songId = selectEl.value ? parseInt(selectEl.value, 10) : null; if (!songId) return; const song = allSongs.find((s) => s.id === songId); if (!song) return; const row = { setlistSongId: null, songId: song.id, title: song.title, artist: song.artist, note: '' }; if (section === 'main') mainRows.push(row); else encoreRows.push(row); renderEdit(); } async function onSaveSongs() { try { const payload = [ ...mainRows.map((r, i) => ({ songId: r.songId, position: i + 1, note: r.note, isEncore: false })), ...encoreRows.map((r, i) => ({ songId: r.songId, position: i + 1, note: r.note, isEncore: true })), ]; setlist = await api.put(`/api/setlists/${setlist.id}/songs`, { songs: payload }); renderReadOnly(); } catch (err) { showError(err.message); } } function showError(message) { document.getElementById('error').innerHTML = `
${escapeHtml(message)}
`; } (async function init() { me = await initNav('setlist'); if (me.isAdmin) { allSongs = await api.get('/api/songs'); } setlist = await api.get('/api/setlists/next'); renderReadOnly(); })();