diff --git a/js/admin.js b/js/admin.js index defd056..d01a804 100644 --- a/js/admin.js +++ b/js/admin.js @@ -7,20 +7,14 @@ let selectedIds = new Set(); let pendingDeleteAction = null; function getStarsHTML(rating) { - // Gère les virgules (ex: "3,5" -> "3.5") et force un nombre let r = parseFloat(String(rating).replace(',', '.')) || 0; - - // Sécurise la note stricte entre 0 et 5 r = Math.min(Math.max(r, 0), 5); - const full = Math.floor(r); const hasHalf = (r - full) >= 0.5; - const empty = Math.max(0, 5 - Math.ceil(r)); // Empêche une valeur négative fatale - + const empty = Math.max(0, 5 - Math.ceil(r)); let html = '★'.repeat(full); if (hasHalf) html += '★'; html += `${'☆'.repeat(empty)}`; - return html; } @@ -74,6 +68,7 @@ document.addEventListener('DOMContentLoaded', () => { function initEventListeners() { const filmForm = document.getElementById('film-form'); if (filmForm) filmForm.addEventListener('submit', saveFilmForm); + const csvInput = document.getElementById('csv-file'); if (csvInput) { csvInput.addEventListener('change', (e) => { @@ -81,10 +76,13 @@ function initEventListeners() { else handleVideothequeUpload(e.target); }); } + const searchInput = document.getElementById('search-input'); if (searchInput) searchInput.addEventListener('input', () => { currentPage = 1; renderAdminTable(); }); + const selectAll = document.getElementById('select-all-checkbox'); if (selectAll) selectAll.addEventListener('change', (e) => toggleSelectAll(e.target)); + document.addEventListener('click', (e) => { if (e.target.classList.contains('modal-close') || e.target.closest('.modal-close')) { const overlay = e.target.closest('.overlay'); @@ -92,6 +90,7 @@ function initEventListeners() { } if (e.target.classList.contains('overlay')) e.target.classList.remove('open'); }); + const physicalFilter = document.getElementById('admin-physical-checkbox'); if (physicalFilter) physicalFilter.addEventListener('change', () => { currentPage = 1; renderAdminTable(); }); } @@ -112,13 +111,12 @@ function renderAdminTable() { const tbody = document.getElementById('admin-table-body'); if (!tbody) return; tbody.innerHTML = ''; - const searchInput = document.getElementById('search-input'); const currentSearch = searchInput ? searchInput.value.toLowerCase() : ''; const physicalFilter = document.getElementById('admin-physical-checkbox'); - + let filtered = allItems.filter(item => item.type === currentAdminTab); - + if (physicalFilter && physicalFilter.checked) { filtered = filtered.filter(f => { if (f.type === 'critique') { @@ -127,7 +125,7 @@ function renderAdminTable() { return true; }); } - + if (currentSearch) { filtered = filtered.filter(f => f.title.toLowerCase().includes(currentSearch) || @@ -163,7 +161,7 @@ function renderAdminTable() { }); renderPagination(totalPages, filtered.length); - + const selectAll = document.getElementById('select-all-checkbox'); if (selectAll) selectAll.checked = pageItems.length > 0 && pageItems.every(f => selectedIds.has(String(f.id))); } @@ -199,7 +197,6 @@ function renderPagination(totalPages, totalItems) { const container = document.getElementById('pagination-container'); if (!container) return; container.innerHTML = ''; - if (totalItems === 0) { container.innerHTML = '
Aucun élément trouvé.
'; return; @@ -217,7 +214,6 @@ function renderPagination(totalPages, totalItems) { prevBtn.onclick = () => { currentPage--; renderAdminTable(); }; container.appendChild(prevBtn); - // Fenêtre glissante : 2 pages avant, 2 pages après la page courante let startPage = Math.max(1, currentPage - 2); let endPage = Math.min(totalPages, currentPage + 2); @@ -226,7 +222,6 @@ function renderPagination(totalPages, totalItems) { firstBtn.textContent = '1'; firstBtn.onclick = () => { currentPage = 1; renderAdminTable(); }; container.appendChild(firstBtn); - if (startPage > 2) { const dots = document.createElement('span'); dots.textContent = '...'; @@ -302,7 +297,7 @@ function switchAdminTab(tabName) { if (wrapper) wrapper.style.display = (tabName === 'videotheque') ? 'none' : 'flex'; document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); document.getElementById(`btn-tab-${tabName}`).classList.add('active'); - updateImportInterface(); + updateImportInterface(); toggleFormFields(); renderAdminTable(); } @@ -413,45 +408,28 @@ async function handleCritiqueUpload(input) { loadDashboardData(); } +// 🔥 NETTOYAGE DES DONNÉES CSV VIDÉOTHÈQUE (Collectorz / CLZ) function normalizeVideothequeRow(row) { - // Bug 1 : EAN float (ex: 7321950374984.0) → chaîne entière sans décimale let ean = row['ean_isbn13'] || row['EAN'] || ''; if (ean !== '') { const eanNum = parseFloat(ean); ean = isNaN(eanNum) ? '' : String(Math.round(eanNum)); } - - // Bug 2 : length float (ex: 245.0) → entier en minutes let length = row['length'] || ''; if (length !== '' && length !== null) { const l = parseFloat(length); length = isNaN(l) ? '' : String(Math.round(l)); } - - // Bug 3 : number_of_discs NaN → 1 let discs = row['number_of_discs'] || ''; if (discs === '' || discs === null || isNaN(parseFloat(discs))) { discs = 1; } else { discs = Math.round(parseFloat(discs)); } - - // Bug 4 : creators contient les acteurs dans ce format CSV, - // first_name/last_name pointent vers le 1er acteur, pas le réalisateur. - // On laisse director vide pour que TMDB le remplisse correctement. - const creators = row['creators'] || ''; - const ensemble = row['ensemble'] || ''; - return Object.assign({}, row, { ean_isbn13: ean, length: length, - number_of_discs: discs, - // Ne pas construire de director depuis first_name/last_name (ce sont des acteurs) - first_name: '', - last_name: '', - // Conserver creators/ensemble pour extraction des acteurs côté PHP - creators: creators, - ensemble: ensemble || creators + number_of_discs: discs }); } @@ -460,8 +438,10 @@ async function handleVideothequeUpload(input) { let allData = []; for (const file of input.files) { try { allData = allData.concat(parseCSV(await file.text())); } catch(e) {} } if (allData.length === 0) { input.value = ''; return alert('❌ Fichier vide.'); } - // Bug 5 : normaliser les données brutes avant envoi + + // 🔥 Application du nettoyage avant envoi au serveur allData = allData.map(normalizeVideothequeRow); + showImportModal(allData.length, 'videotheque'); let processed = 0; for (let i = 0; i < allData.length; i += 10) {