diff --git a/js/admin.js b/js/admin.js index 9e42099..987a929 100644 --- a/js/admin.js +++ b/js/admin.js @@ -42,11 +42,10 @@ function parseCSV(text) { } if (col !== '' || row.length > 0) { row.push(col); rows.push(row); } if (rows.length === 0) return []; - const headers = rows[0].map(h => h.trim()); const data = []; for (let i = 1; i < rows.length; i++) { - if (rows[i].length === 1 && rows[i][0].trim() === '') continue; // Ignore les lignes 100% vides + if (rows[i].length === 1 && rows[i][0].trim() === '') continue; const obj = {}; headers.forEach((h, idx) => { obj[h] = rows[i][idx] !== undefined ? rows[i][idx] : ''; @@ -71,7 +70,6 @@ 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) => handleCsvUpload(e.target)); @@ -84,9 +82,7 @@ function initEventListeners() { } const selectAll = document.getElementById('select-all-checkbox'); - if (selectAll) { - selectAll.addEventListener('change', (e) => toggleSelectAll(e.target)); - } + 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')) { @@ -97,7 +93,7 @@ function initEventListeners() { e.target.classList.remove('open'); } }); - + const physicalFilter = document.getElementById('admin-physical-checkbox'); if (physicalFilter) { physicalFilter.addEventListener('change', () => { @@ -123,7 +119,6 @@ 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'); @@ -173,7 +168,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))); @@ -184,7 +179,6 @@ function toggleSingleSelect(id, checkbox) { if (checkbox.checked) selectedIds.add(String(id)); else selectedIds.delete(String(id)); updateBulkBar(); - const filtered = allItems.filter(item => item.type === currentAdminTab); const selectAll = document.getElementById('select-all-checkbox'); if (selectAll) { @@ -222,7 +216,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; @@ -345,7 +338,6 @@ function switchAdminTab(tabName) { selectedIds.clear(); const searchInput = document.getElementById('search-input'); if (searchInput) searchInput.value = ''; - const physicalFilter = document.getElementById('admin-physical-checkbox'); if (physicalFilter) physicalFilter.checked = false; @@ -391,8 +383,8 @@ function openEditModal(id) { function closeAdminModal() { document.getElementById('admin-modal').classList.remove('open'); } -async function openConfigModal() { - document.getElementById('config-modal').classList.add('open'); +async function openConfigModal() { + document.getElementById('config-modal').classList.add('open'); document.getElementById('tmdb-key-input').placeholder = 'Pour les critiques (réalisateur, streaming)'; try { const res = await fetch(`${API_URL}?action=get_config_keys`, { headers: { 'Authorization': localStorage.getItem('token') } }); @@ -446,13 +438,11 @@ async function saveFilmForm(e) { } catch (err) { console.error('Erreur sauvegarde :', err); } } -// --- FONCTION D'IMPORT INTELLIGENTE --- +// --- FONCTION D'IMPORT INTELLIGENTE (CORRIGÉE) --- async function handleCsvUpload(input) { if (!input.files || input.files.length === 0) return; - let allData = []; - - // 1. Lecture de tous les fichiers (supporte le multi-upload) + for (const file of input.files) { try { const text = await file.text(); @@ -462,16 +452,14 @@ async function handleCsvUpload(input) { console.error('Erreur lecture fichier', file.name, e); } } - - input.value = ''; // Reset l'input file - + + input.value = ''; + if (allData.length === 0) { alert('❌ Fichiers vides ou mal formatés.'); return; } - // 2. Fusion et Dédoublonnage en mémoire - // Utilise une Map pour regrouper les données par "Titre|Année" const mergedMap = new Map(); allData.forEach(row => { const title = (row['Title'] || row['Name'] || '').trim(); @@ -483,7 +471,6 @@ async function handleCsvUpload(input) { mergedMap.set(key, { ...row }); } else { const existing = mergedMap.get(key); - // Fusion des notes et critiques si présentes if ((row['Rating'] || row['rating']) && !existing['Rating']) existing['Rating'] = row['Rating']; if ((row['Review'] || row['review']) && !existing['Review']) existing['Review'] = row['Review']; } @@ -491,7 +478,7 @@ async function handleCsvUpload(input) { let finalData = Array.from(mergedMap.values()); - // 3. Protection : Ne pas écraser les données BDD existantes + // 🔥 CORRECTION : Mapping des champs CSV vers les champs attendus par le Backend finalData = finalData.map(row => { const title = (row['Title'] || row['Name'] || '').trim(); const dateStr = (row['Date'] || row['Year'] || row['year'] || '').toString(); @@ -503,23 +490,21 @@ async function handleCsvUpload(input) { f.type === currentAdminTab ); - if (existingDb) { - return { - ...row, - 'Rating': (row['Rating'] || row['rating']) || existingDb.rating, - 'Review': (row['Review'] || row['review']) || existingDb.review - }; - } - return row; + return { + ...row, // Garde les données brutes au cas où + // Mappe vers les noms de colonnes BDD + title: title, + year: year, + rating: (row['Rating'] || row['rating']) || (existingDb ? existingDb.rating : ''), + review: (row['Review'] || row['review']) || (existingDb ? existingDb.review : '') + }; }); - // 4. Lancement de la modale de progression stylisée showImportModal(finalData.length, currentAdminTab); - // 5. Envoi par lots de 10 const batchSize = 10; let processed = 0; - + for (let i = 0; i < finalData.length; i += batchSize) { const batch = finalData.slice(i, i + batchSize); try { @@ -537,8 +522,7 @@ async function handleCsvUpload(input) { processed += batch.length; updateImportModal(processed, finalData.length); } - - // 6. Finalisation + closeImportModal(); alert(`✅ Import terminé ! ${finalData.length} élément(s) traité(s).`); loadDashboardData(); @@ -604,17 +588,12 @@ function showImportModal(total, type) { const modal = document.getElementById('import-progress-modal'); const title = document.getElementById('import-modal-title'); const desc = document.getElementById('import-modal-desc'); - - // Adaptation selon le contexte title.innerHTML = type === 'critique' ? ' Import des Critiques' : ' Import Vidéothèque'; - desc.textContent = `Traitement de ${total} élément(s)...`; - document.getElementById('import-progress-bar').style.width = '0%'; document.getElementById('import-modal-counter').textContent = '0%'; - modal.classList.add('open'); } @@ -632,7 +611,6 @@ async function fetchInfoFromEAN() { const eanInput = document.getElementById('f-ean'); const ean = eanInput.value.trim(); if (!ean || ean.length < 8) { alert("Veuillez saisir un code EAN valide."); return; } - const btn = eanInput.nextElementSibling; const originalHtml = btn.innerHTML; btn.innerHTML = ''; @@ -656,7 +634,7 @@ async function fetchInfoFromEAN() { if (d.aspect_ratio) document.getElementById('f-aspect').value = d.aspect_ratio; } else { alert("Aucune information trouvée pour ce code EAN."); } } catch (e) { - console.error("Erreur de recherche EAN:", e); + console.error("Erreur de recherche EAN: ", e); alert("Erreur réseau lors de la recherche du code EAN."); } finally { btn.innerHTML = originalHtml; @@ -667,7 +645,6 @@ async function fetchInfoFromEAN() { function updateImportInterface() { const title = document.getElementById('import-title'); const desc = document.getElementById('import-desc'); - if (currentAdminTab === 'critique') { title.innerHTML = 'Importer Critiques & Notes'; desc.textContent = 'Glissez-déposez vos fichiers "ratings.csv" et "reviews.csv" (Letterboxd).';