let me = null;
let suggestions = [];
const expanded = new Set();
async function loadSuggestions() {
suggestions = await api.get('/api/suggestions');
renderSuggestions();
}
function statusLabel(status) {
return { pending: 'En attente', approved: 'Approuvé', rejected: 'Rejeté' }[status] || status;
}
function suggestionTemplate(s) {
const isOpen = expanded.has(s.id);
const embed = youtubeEmbedUrl(s.youtube_url);
return `
✔ ${s.approve_count}
✘ ${s.reject_count}
`;
}
function detailTemplate(s) {
const embed = youtubeEmbedUrl(s.youtube_url);
const myVote = s.votes.find((v) => v.user_id === me.id);
return `
${embed ? `` : `${escapeHtml(s.youtube_url)}
`}
${s.votes.length ? s.votes.map(voteItemTemplate).join('') : '
Aucun vote pour le moment.
'}
${me.isAdmin ? `
` : ''}
`;
}
function voteItemTemplate(v) {
const icon = v.vote === 'approve' ? '✔' : '✘';
return `
${escapeHtml(v.voter_name)} ${icon}
${v.comment ? `— ${escapeHtml(v.comment)}` : ''}
`;
}
function renderSuggestions() {
const container = document.getElementById('suggestions-list');
renderList(container, suggestions, suggestionTemplate, 'Aucune suggestion pour le moment.');
document.querySelectorAll('.toggle-detail').forEach((btn) => {
btn.addEventListener('click', () => onToggleDetail(parseInt(btn.dataset.id, 10)));
});
}
async function onToggleDetail(id) {
if (expanded.has(id)) {
expanded.delete(id);
} else {
expanded.add(id);
}
renderSuggestions();
if (expanded.has(id)) {
await loadDetail(id);
}
}
async function loadDetail(id) {
try {
const detail = await api.get(`/api/suggestions/${id}`);
const container = document.querySelector(`[data-detail-for="${id}"]`);
if (!container) return;
container.innerHTML = detailTemplate(detail);
container.querySelector('.vote-form').addEventListener('submit', (e) => onVote(e, id));
const promoteBtn = container.querySelector('.promote-btn');
if (promoteBtn) promoteBtn.addEventListener('click', () => onPromote(id));
const rejectBtn = container.querySelector('.reject-btn');
if (rejectBtn) rejectBtn.addEventListener('click', () => onReject(id));
const deleteBtn = container.querySelector('.delete-btn');
if (deleteBtn) deleteBtn.addEventListener('click', () => onDelete(id));
} catch (err) {
showError(err.message);
}
}
async function onVote(e, id) {
e.preventDefault();
const form = e.target;
const vote = form.vote.value;
const comment = form.comment.value.trim();
try {
await api.post(`/api/suggestions/${id}/vote`, { vote, comment });
await loadSuggestions();
expanded.add(id);
renderSuggestions();
await loadDetail(id);
} catch (err) {
showError(err.message);
}
}
async function onPromote(id) {
try {
await api.post(`/api/suggestions/${id}/promote`, {});
await loadSuggestions();
expanded.add(id);
renderSuggestions();
await loadDetail(id);
} catch (err) {
showError(err.message);
}
}
async function onReject(id) {
try {
await api.patch(`/api/suggestions/${id}`, { status: 'rejected' });
await loadSuggestions();
expanded.add(id);
renderSuggestions();
await loadDetail(id);
} catch (err) {
showError(err.message);
}
}
async function onDelete(id) {
try {
await api.del(`/api/suggestions/${id}`);
expanded.delete(id);
await loadSuggestions();
} catch (err) {
showError(err.message);
}
}
async function onAddSuggestion(e) {
e.preventDefault();
const form = e.target;
const title = form.title.value.trim();
const artist = form.artist.value.trim();
const youtubeUrl = form.youtubeUrl.value.trim();
try {
await api.post('/api/suggestions', { title, artist, youtubeUrl });
form.reset();
await loadSuggestions();
} catch (err) {
showError(err.message);
}
}
function showError(message) {
document.getElementById('error').innerHTML = `${escapeHtml(message)}
`;
}
(async function init() {
me = await initNav('suggestions');
document.getElementById('add-suggestion-form').addEventListener('submit', onAddSuggestion);
await loadSuggestions();
})();