diff --git a/js/admin.js b/js/admin.js index a71b905..2ae02c0 100644 --- a/js/admin.js +++ b/js/admin.js @@ -1,41 +1,49 @@ const API_URL = '../api.php'; let allItems = []; let currentAdminTab = 'critique'; -let editingItemId = null; +// ── INITIALISATION ── document.addEventListener('DOMContentLoaded', () => { loadDashboardData(); - initModals(); - initForms(); + + // Attacher l'événement pour la modale de suppression + const confirmBtn = document.getElementById('confirm-btn'); + if(confirmBtn) { + confirmBtn.addEventListener('click', () => { + if (pendingDeleteAction) pendingDeleteAction(); + closeConfirmModal(); + }); + } }); async function loadDashboardData() { try { const res = await fetch(`${API_URL}?action=get_films`); - if (!res.ok) throw new Error('Erreur de chargement'); allItems = await res.json(); + + const secRes = await fetch(`${API_URL}?action=check_security_status`); + const secData = await secRes.json(); + const banner = document.getElementById('security-banner'); + if (banner) banner.style.display = secData.is_blank ? 'flex' : 'none'; + renderAdminTable(); - } catch (error) { - console.error("Erreur loadDashboardData:", error); - } + } catch (err) { console.error('Erreur chargement :', err); } } function renderAdminTable() { const tbody = document.getElementById('admin-table-body'); if (!tbody) return; tbody.innerHTML = ''; - const filtered = allItems.filter(item => item.type === currentAdminTab); - const countLabel = document.getElementById('admin-count-label'); - if (countLabel) countLabel.textContent = `${filtered.length} élément(s)`; - // BUG CORRIGÉ : f = > remplacé par f => - // Nettoyage des espaces parasites dans les balises HTML + const countLabel = document.getElementById('admin-count-label'); + if(countLabel) countLabel.textContent = `${filtered.length} élément(s)`; + filtered.forEach(f => { const tr = document.createElement('tr'); tr.innerHTML = ` - + ${f.poster ? `Affiche` : '
'} @@ -54,6 +62,7 @@ function renderAdminTable() { }); } +// ── GESTION DE MASSE ── function toggleSelectAll(source) { document.querySelectorAll('.film-checkbox').forEach(cb => cb.checked = source.checked); updateBulkBar(); @@ -63,23 +72,20 @@ function updateBulkBar() { const checked = document.querySelectorAll('.film-checkbox:checked'); const bulkBar = document.getElementById('bulk-actions-bar'); const bulkCount = document.getElementById('bulk-count'); + if (checked.length > 0) { - bulkBar.style.display = 'flex'; - bulkCount.textContent = checked.length; + if(bulkBar) bulkBar.style.display = 'flex'; + if(bulkCount) bulkCount.textContent = checked.length; } else { - bulkBar.style.display = 'none'; + if(bulkBar) bulkBar.style.display = 'none'; const selectAll = document.getElementById('select-all-checkbox'); if(selectAll) selectAll.checked = false; } } -document.addEventListener('change', (e) => { - if (e.target.classList.contains('film-checkbox')) { - updateBulkBar(); - } -}); - +// ── POP-UP CONFIRMATION SUPPRESSION ── let pendingDeleteAction = null; + function showConfirmModal(actionFn) { pendingDeleteAction = actionFn; const modal = document.getElementById('confirm-modal'); @@ -89,123 +95,154 @@ function showConfirmModal(actionFn) { function closeConfirmModal() { const modal = document.getElementById('confirm-modal'); if(modal) modal.classList.remove('open'); + pendingDeleteAction = null; } -document.getElementById('confirm-btn')?.addEventListener('click', () => { - if (pendingDeleteAction) pendingDeleteAction(); - closeConfirmModal(); -}); - +// ── ACTIONS CRUD (SUPPRESSION) ── async function executeBulkDelete() { + const ids = Array.from(document.querySelectorAll('.film-checkbox:checked')).map(cb => cb.value); + if (ids.length === 0) return; + showConfirmModal(async () => { - const ids = Array.from(document.querySelectorAll('.film-checkbox:checked')).map(cb => cb.value); - await fetch(`${API_URL}?action=bulk_delete`, { - method: 'POST', - headers: { 'Authorization': localStorage.getItem('token'), 'Content-Type': 'application/json' }, - body: JSON.stringify({ ids, type: currentAdminTab }) - }); - loadDashboardData(); - updateBulkBar(); + try { + await fetch(`${API_URL}?action=bulk_delete`, { + method: 'POST', + headers: { 'Authorization': localStorage.getItem('token'), 'Content-Type': 'application/json' }, + body: JSON.stringify({ ids, type: currentAdminTab }) + }); + + document.getElementById('bulk-actions-bar').style.display = 'none'; + const selectAll = document.getElementById('select-all-checkbox'); + if(selectAll) selectAll.checked = false; + + loadDashboardData(); + } catch (err) { console.error('Erreur bulk delete :', err); } }); } async function deleteSingleFilm(id) { showConfirmModal(async () => { - await fetch(`${API_URL}?action=delete_film&id=${id}&type=${currentAdminTab}`, { - method: 'DELETE', - headers: { 'Authorization': localStorage.getItem('token') } - }); - loadDashboardData(); + try { + await fetch(`${API_URL}?action=delete_film&id=${id}&type=${currentAdminTab}`, { + method: 'DELETE', + headers: { 'Authorization': localStorage.getItem('token') } + }); + loadDashboardData(); + } catch (err) { console.error('Erreur delete :', err); } }); } +// ── ACTIONS CRUD (SAUVEGARDE) ── +async function saveFilmForm(e) { + e.preventDefault(); + const payload = { + type: currentAdminTab, + id: document.getElementById('f-id').value, + title: document.getElementById('f-title').value, + year: document.getElementById('f-year').value, + director: document.getElementById('f-director').value, + poster: document.getElementById('f-poster').value, + rating: document.getElementById('f-rating') ? document.getElementById('f-rating').value : '', + review: document.getElementById('f-review') ? document.getElementById('f-review').value : '', + streaming: document.getElementById('f-streaming') ? document.getElementById('f-streaming').value : '', + format: document.getElementById('f-format') ? document.getElementById('f-format').value : '', + length: document.getElementById('f-length') ? document.getElementById('f-length').value : '', + publisher: document.getElementById('f-publisher') ? document.getElementById('f-publisher').value : '', + ean_isbn13: document.getElementById('f-ean') ? document.getElementById('f-ean').value : '', + number_of_discs: document.getElementById('f-discs') ? document.getElementById('f-discs').value : '', + aspect_ratio: document.getElementById('f-aspect') ? document.getElementById('f-aspect').value : '', + description: document.getElementById('f-description') ? document.getElementById('f-description').value : '' + }; + + await fetch(`${API_URL}?action=save_film`, { + method: 'POST', + headers: { 'Authorization': localStorage.getItem('token'), 'Content-Type': 'application/json' }, + body: JSON.stringify(payload) + }); + closeAdminModal(); + loadDashboardData(); +} + +// ── MODALES & UI ── function switchAdminTab(tabName) { currentAdminTab = tabName; - document.querySelectorAll('.tab-btn').forEach(b => b.classList.toggle('active', b.id === `btn-tab-${tabName}`)); + document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); + const btn = document.getElementById(`btn-tab-${tabName}`); + if(btn) btn.classList.add('active'); + + document.getElementById('form-critique-fields').style.display = tabName === 'critique' ? 'block' : 'none'; + document.getElementById('form-videotheque-fields').style.display = tabName === 'videotheque' ? 'block' : 'none'; + renderAdminTable(); } -// --- AJOUTS FONCTIONNELS MANQUANTS --- +function openAddModal() { + document.getElementById('film-form').reset(); + document.getElementById('f-id').value = ''; + document.getElementById('admin-modal').classList.add('open'); +} function openEditModal(id) { - const item = allItems.find(i => i.id == id); + const item = allItems.find(x => String(x.id) === String(id)); if (!item) return; - editingItemId = id; - const modal = document.getElementById('edit-modal'); - if (!modal) return; + document.getElementById('f-id').value = item.id; + document.getElementById('f-title').value = item.title; + document.getElementById('f-year').value = item.year || ''; + document.getElementById('f-director').value = item.director || ''; + document.getElementById('f-poster').value = item.poster || ''; - const setVal = (id, val) => { const el = document.getElementById(id); if (el) el.value = val || ''; }; - setVal('film-title', item.title); - setVal('film-year', item.year); - setVal('film-director', item.director); - setVal('film-poster', item.poster); - setVal('film-rating', item.rating); - setVal('film-review', item.review); - setVal('film-streaming', item.streaming); - setVal('film-format', item.format); - setVal('film-length', item.length); - setVal('film-publisher', item.publisher); - setVal('film-aspect-ratio', item.aspect_ratio); - setVal('film-ean', item.ean_isbn13); - setVal('film-discs', item.number_of_discs); - setVal('film-description', item.description); + if(currentAdminTab === 'critique') { + document.getElementById('f-rating').value = item.rating || 3; + document.getElementById('f-review').value = item.review || ''; + document.getElementById('f-streaming').value = item.streaming || ''; + } else { + document.getElementById('f-format').value = item.format || ''; + document.getElementById('f-length').value = item.length || ''; + document.getElementById('f-publisher').value = item.publisher || ''; + document.getElementById('f-aspect').value = item.aspect_ratio || ''; + document.getElementById('f-ean').value = item.ean_isbn13 || ''; + document.getElementById('f-discs').value = item.number_of_discs || 1; + document.getElementById('f-description').value = item.description || ''; + } - modal.classList.add('open'); + document.getElementById('admin-modal').classList.add('open'); } -function initModals() { - document.querySelectorAll('.modal-close, .btn-cancel').forEach(btn => { - btn.addEventListener('click', (e) => { - const overlay = e.target.closest('.overlay'); - if (overlay) overlay.classList.remove('open'); - }); - }); - document.querySelectorAll('.overlay').forEach(overlay => { - overlay.addEventListener('click', (e) => { - if (e.target === overlay) overlay.classList.remove('open'); - }); - }); +function closeAdminModal() { document.getElementById('admin-modal').classList.remove('open'); } +function openConfigModal() { document.getElementById('config-modal').classList.add('open'); } +function closeConfigModal() { document.getElementById('config-modal').classList.remove('open'); } +function openPasswordModal() { document.getElementById('password-modal').classList.add('open'); } +function closePasswordModal() { document.getElementById('password-modal').classList.remove('open'); } + +function logout() { + localStorage.removeItem('token'); + window.location.href = 'login.html'; } -function initForms() { - const filmForm = document.getElementById('film-form'); - if (filmForm) { - filmForm.addEventListener('submit', async (e) => { - e.preventDefault(); - const formData = new FormData(filmForm); - const data = Object.fromEntries(formData.entries()); - data.id = editingItemId; - data.type = currentAdminTab; - - const action = editingItemId ? 'update_film' : 'add_film'; - await fetch(`${API_URL}?action=${action}`, { - method: 'POST', - headers: { 'Authorization': localStorage.getItem('token'), 'Content-Type': 'application/json' }, - body: JSON.stringify(data) - }); - - document.getElementById('edit-modal')?.classList.remove('open'); - editingItemId = null; - loadDashboardData(); - }); - } +// ── MOT DE PASSE ── +async function saveNewPassword() { + const newPwd = document.getElementById('new-password-input').value; + const confirmPwd = document.getElementById('new-password-confirm').value; + if (newPwd !== confirmPwd) return alert("Les mots de passe ne correspondent pas."); + + const res = await fetch(`${API_URL}?action=update_password`, { + method: 'POST', + headers: { 'Authorization': localStorage.getItem('token'), 'Content-Type': 'application/json' }, + body: JSON.stringify({ new_password: newPwd }) + }); + if (res.ok) { alert("Mot de passe mis à jour."); closePasswordModal(); } +} - const csvInput = document.getElementById('csv-file'); - if (csvInput) { - csvInput.addEventListener('change', async (e) => { - const file = e.target.files[0]; - if (!file) return; - const formData = new FormData(); - formData.append('file', file); - formData.append('type', currentAdminTab); - - await fetch(`${API_URL}?action=import_csv`, { - method: 'POST', - headers: { 'Authorization': localStorage.getItem('token') }, - body: formData - }); - loadDashboardData(); - }); - } +// ── IMPORT CSV ── +async function handleCsvUpload(input) { + if (!input.files[0]) return; + const formData = new FormData(); + formData.append('csv_file', input.files[0]); + await fetch(`${API_URL}?action=import_csv`, { + method: 'POST', + headers: { 'Authorization': localStorage.getItem('token') }, + body: formData + }); + loadDashboardData(); } \ No newline at end of file