/* Module administration - Backoffice complet */ // Mapping toggle ID -> cle config fonctionnalites const TOGGLES_MAP = { 'tog-photo-simple': 'photo_simple', 'tog-multi-shot': 'multi_shot', 'tog-filtres': 'filtres', 'tog-overlays': 'overlays', 'tog-chroma-key': 'chroma_key', 'tog-impression': 'impression', 'tog-email': 'email', 'tog-qr-code': 'qr_code', 'tog-galerie': 'galerie', }; async function chargerAdmin() { config = await apiGet('/api/config'); chargerMateriel(); chargerCompteur(); chargerDestinations(); chargerCadres(); chargerAnimations(); chargerFonctionnalites(); chargerEmailAdmin(); chargerGalerieAdmin(); } // === MATERIEL === async function chargerMateriel() { const cam = config.camera || {}; const imp = config.impression || {}; // Camera const statut = await apiGet('/api/camera/statut'); const badge = document.getElementById('admin-camera-statut'); badge.textContent = statut.connectee ? 'Connectee' : 'Deconnectee'; badge.style.background = statut.connectee ? 'rgba(76,175,80,0.2)' : 'rgba(244,67,54,0.2)'; badge.style.color = statut.connectee ? 'var(--succes)' : 'var(--danger)'; // Liste appareils const selectApp = document.getElementById('admin-appareil'); selectApp.innerHTML = ''; for (const a of statut.appareils) { const opt = document.createElement('option'); opt.value = a; opt.textContent = a; selectApp.appendChild(opt); } if (cam.appareil) selectApp.value = cam.appareil; setValue('admin-car', cam.compte_a_rebours || 3); // Imprimantes await rafraichirImprimantes(); if (imp.imprimante) document.getElementById('admin-imprimante').value = imp.imprimante; setValue('admin-copies-max', imp.copies_max || 5); } async function rafraichirImprimantes() { const imprimantes = await apiGet('/api/imprimantes'); const select = document.getElementById('admin-imprimante'); select.innerHTML = ''; for (const p of imprimantes) { const opt = document.createElement('option'); opt.value = p.nom; opt.textContent = `${p.nom} (${p.statut})`; select.appendChild(opt); } } async function reconnecterCamera() { const resultat = await apiPost('/api/camera/reconnecter'); chargerMateriel(); } async function sauvegarderMateriel() { await apiPost('/api/config', { camera: { appareil: getValue('admin-appareil'), compte_a_rebours: parseInt(getValue('admin-car')) || 3, }, impression: { imprimante: getValue('admin-imprimante'), copies_max: parseInt(getValue('admin-copies-max')) || 5, }, }); afficherStatut('Materiel sauvegarde', 'succes'); } // === COMPTEUR === async function chargerCompteur() { const etat = await apiGet('/api/compteur'); document.getElementById('tog-compteur-actif').checked = etat.actif; document.getElementById('admin-compteur-restant').textContent = etat.restantes; document.getElementById('admin-compteur-limite-display').textContent = etat.limite; setValue('admin-compteur-limite', etat.limite); } async function sauvegarderCompteur() { await apiPost('/api/config', { compteur: { actif: document.getElementById('tog-compteur-actif').checked, limite: parseInt(getValue('admin-compteur-limite')) || 400, }, }); chargerCompteur(); afficherStatut('Compteur sauvegarde', 'succes'); } async function resetCompteur() { if (confirm('Remettre le compteur a zero ?')) { await apiPost('/api/compteur/reset'); chargerCompteur(); afficherStatut('Compteur remis a zero', 'succes'); } } // === DESTINATIONS === function chargerDestinations() { const dest = config.destinations || {}; document.getElementById('tog-dest-memoire').checked = dest.memoire_interne !== false; document.getElementById('tog-dest-usb').checked = dest.cle_usb || false; document.getElementById('tog-dest-ftp').checked = dest.ftp || false; document.getElementById('tog-dest-web').checked = dest.site_web || false; document.getElementById('tog-dest-email-auto').checked = dest.email_auto || false; // Sous-configs visibles si actives toggleSousConfig('tog-dest-usb', 'dest-usb-details'); toggleSousConfig('tog-dest-ftp', 'dest-ftp-details'); toggleSousConfig('tog-dest-web', 'dest-web-details'); setValue('admin-ftp-host', dest.ftp_host); setValue('admin-ftp-port', dest.ftp_port || 21); setValue('admin-ftp-user', dest.ftp_user); setValue('admin-ftp-pass', dest.ftp_password); setValue('admin-ftp-chemin', dest.ftp_chemin || '/photobooth'); setValue('admin-web-url', dest.site_web_url); // Radio sauvegarder tout / imprimees if (dest.sauvegarder_tout === false) { document.getElementById('sauv-imprimees').checked = true; } else { document.getElementById('sauv-tout').checked = true; } // Listeners pour afficher/cacher sous-configs ['tog-dest-usb', 'tog-dest-ftp', 'tog-dest-web'].forEach(id => { const el = document.getElementById(id); el.onchange = () => { const map = { 'tog-dest-usb': 'dest-usb-details', 'tog-dest-ftp': 'dest-ftp-details', 'tog-dest-web': 'dest-web-details' }; toggleSousConfig(id, map[id]); }; }); } function toggleSousConfig(toggleId, detailsId) { const checked = document.getElementById(toggleId).checked; const el = document.getElementById(detailsId); if (checked) el.classList.remove('cache'); else el.classList.add('cache'); } async function detecterUSB() { const usbs = await apiGet('/api/usb/detecter'); const select = document.getElementById('admin-chemin-usb'); select.innerHTML = ''; if (usbs.length === 0) { const opt = document.createElement('option'); opt.value = ''; opt.textContent = 'Aucune cle detectee'; select.appendChild(opt); } else { for (const u of usbs) { const opt = document.createElement('option'); opt.value = u; opt.textContent = u; select.appendChild(opt); } } } async function sauvegarderDestinations() { await apiPost('/api/config', { destinations: { memoire_interne: document.getElementById('tog-dest-memoire').checked, cle_usb: document.getElementById('tog-dest-usb').checked, chemin_usb: getValue('admin-chemin-usb') || '/media/usb', ftp: document.getElementById('tog-dest-ftp').checked, ftp_host: getValue('admin-ftp-host'), ftp_port: parseInt(getValue('admin-ftp-port')) || 21, ftp_user: getValue('admin-ftp-user'), ftp_password: getValue('admin-ftp-pass'), ftp_chemin: getValue('admin-ftp-chemin') || '/photobooth', site_web: document.getElementById('tog-dest-web').checked, site_web_url: getValue('admin-web-url'), email_auto: document.getElementById('tog-dest-email-auto').checked, sauvegarder_tout: document.getElementById('sauv-tout').checked, }, }); afficherStatut('Destinations sauvegardees', 'succes'); } // === CADRES === async function chargerCadres() { const data = await apiGet('/api/cadres'); const liste = document.getElementById('liste-cadres'); liste.innerHTML = ''; if (data.tous.length === 0) { liste.innerHTML = '

Aucun cadre importe

'; return; } for (const nom of data.tous) { const div = document.createElement('div'); div.className = 'cadre-item'; const cb = document.createElement('input'); cb.type = 'checkbox'; cb.checked = data.actifs.includes(nom); cb.onchange = () => majCadresActifs(); const img = document.createElement('img'); img.src = `/assets/overlays/${nom}`; img.alt = nom; const span = document.createElement('span'); span.textContent = nom.replace('.png', ''); div.appendChild(cb); div.appendChild(img); div.appendChild(span); liste.appendChild(div); } } async function majCadresActifs() { const items = document.querySelectorAll('.cadre-item input[type="checkbox"]'); const noms = document.querySelectorAll('.cadre-item span'); const actifs = []; items.forEach((cb, i) => { if (cb.checked) actifs.push(noms[i].textContent + '.png'); }); await apiPost('/api/cadres', { actifs }); } async function uploaderCadre() { const input = document.getElementById('input-cadre'); if (!input.files.length) return; const formData = new FormData(); formData.append('fichier', input.files[0]); await fetch('/api/upload/overlay', { method: 'POST', body: formData }); input.value = ''; chargerCadres(); afficherStatut('Cadre importe', 'succes'); } // === ANIMATIONS === let animationChoisie = 'classique'; async function chargerAnimations() { const anims = await apiGet('/api/animations'); animationChoisie = config.camera?.animation_compte_a_rebours || 'classique'; const liste = document.getElementById('liste-animations'); liste.innerHTML = ''; for (const [id, nom] of Object.entries(anims)) { const div = document.createElement('div'); div.className = 'anim-option' + (id === animationChoisie ? ' actif' : ''); div.textContent = nom; div.onclick = () => choisirAnimation(id, div); liste.appendChild(div); } } async function choisirAnimation(id, el) { animationChoisie = id; document.querySelectorAll('.anim-option').forEach(e => e.classList.remove('actif')); el.classList.add('actif'); await apiPost('/api/config', { camera: { animation_compte_a_rebours: id }, }); testerAnimation(); } const EMOJI_MAP = { 3: '🤪', 2: '😱', 1: '🔥' }; function testerAnimation() { const chiffre = document.getElementById('preview-anim-chiffre'); let count = 3; function afficher() { if (animationChoisie === 'emoji') { chiffre.textContent = EMOJI_MAP[count] || count; } else { chiffre.textContent = count; } // Reset : retirer toute classe d'animation chiffre.className = 'anim-chiffre'; // Force reflow pour que le navigateur enregistre le retrait void chiffre.offsetWidth; // Appliquer la nouvelle animation chiffre.classList.add('anim-' + animationChoisie); count--; if (count > 0) setTimeout(afficher, 1000); } afficher(); } // === FONCTIONNALITES === function chargerFonctionnalites() { const fonc = config.fonctionnalites || {}; for (const [id, cle] of Object.entries(TOGGLES_MAP)) { const el = document.getElementById(id); if (el) el.checked = fonc[cle] !== false; } setupToggleListeners(); } function setupToggleListeners() { for (const [id, cle] of Object.entries(TOGGLES_MAP)) { const el = document.getElementById(id); if (!el) continue; const nouveau = el.cloneNode(true); el.parentNode.replaceChild(nouveau, el); nouveau.addEventListener('change', () => { apiPost('/api/config', { fonctionnalites: { [cle]: nouveau.checked } }); }); } } // === EVENEMENT === function chargerEvenementAdmin() { const event = config.evenement || {}; setValue('admin-nom-event', event.nom); setValue('admin-couleur-primaire', event.couleur_primaire || '#e91e63'); setValue('admin-couleur-secondaire', event.couleur_secondaire || '#ffffff'); } async function sauvegarderEvenement() { await apiPost('/api/config', { evenement: { nom: getValue('admin-nom-event'), couleur_primaire: getValue('admin-couleur-primaire'), couleur_secondaire: getValue('admin-couleur-secondaire'), }, }); afficherStatut('Evenement sauvegarde', 'succes'); } // === EMAIL === function chargerEmailAdmin() { const email = config.email || {}; setValue('admin-smtp-host', email.smtp_host); setValue('admin-smtp-port', email.smtp_port || 587); setValue('admin-smtp-user', email.smtp_user); setValue('admin-smtp-pass', email.smtp_password); setValue('admin-expediteur', email.expediteur); } async function sauvegarderEmail() { await apiPost('/api/config', { email: { smtp_host: getValue('admin-smtp-host'), smtp_port: parseInt(getValue('admin-smtp-port')) || 587, smtp_user: getValue('admin-smtp-user'), smtp_password: getValue('admin-smtp-pass'), expediteur: getValue('admin-expediteur'), }, }); afficherStatut('Email sauvegarde', 'succes'); } // === GALERIE === async function chargerGalerieAdmin() { const compteur = await apiGet('/api/galerie/compteur'); document.getElementById('admin-nb-photos').textContent = compteur.photos_prises || 0; document.getElementById('admin-nb-exports').textContent = compteur.exports || 0; setValue('admin-url-galerie', (config.qr_code || {}).url_galerie); } async function sauvegarderGalerie() { await apiPost('/api/config', { qr_code: { url_galerie: getValue('admin-url-galerie') }, }); afficherStatut('Configuration sauvegardee', 'succes'); } function confirmerViderGalerie() { if (confirm('Supprimer TOUTES les photos ? Cette action est irreversible.')) { apiPost('/api/galerie/vider').then(() => { afficherStatut('Galerie videe', 'succes'); chargerGalerieAdmin(); }); } } // === SYSTEME === function confirmerRedemarrage() { if (confirm('Redemarrer le systeme ?')) apiPost('/api/systeme/redemarrer'); } function confirmerExtinction() { if (confirm('Eteindre le systeme ?')) apiPost('/api/systeme/eteindre'); } // === Utilitaires === function setValue(id, val) { const el = document.getElementById(id); if (el) el.value = val || ''; } function getValue(id) { const el = document.getElementById(id); return el ? el.value : ''; }