/* 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(); chargerCadresImpression(); chargerAnimations(); chargerFonctionnalites(); chargerEmailAdmin(); chargerFondsAdmin(); chargerGalerieAdmin(); chargerBoothAdmin(); } // === 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.source; opt.textContent = `${a.nom} [${a.type}]`; if (a.source === statut.mode || a.source === cam.appareil) opt.selected = true; selectApp.appendChild(opt); } if (cam.appareil) selectApp.value = cam.appareil; setValue('admin-car', cam.compte_a_rebours || 3); // Imprimantes await rafraichirImprimantes(); rafraichirStatutImprimante(); if (imp.imprimante) document.getElementById('admin-imprimante').value = imp.imprimante; if (imp.format) document.getElementById('admin-format-papier').value = imp.format; const fmt = (imp.format || '15x20').replace('-2up', ''); const orient = (imp.orientations || {})[fmt] || 'portrait'; document.querySelector(`input[name="admin-orientation"][value="${orient}"]`).checked = true; 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 source = getValue('admin-appareil') || null; const resultat = await apiPost('/api/camera/reconnecter', { source }); chargerMateriel(); } function _getOrientations() { const fmt = (getValue('admin-format-papier') || '15x20').replace('-2up', ''); const orient = document.querySelector('input[name="admin-orientation"]:checked')?.value || 'portrait'; // On conserve les orientations des autres formats depuis la config courante const existing = (config.impression || {}).orientations || {}; return { ...existing, [fmt]: orient }; } async function couperPapier() { afficherStatut('Envoi commande coupe...', 'succes'); const r = await apiPost('/api/imprimante/couper', {}); afficherStatut(r.message, r.succes ? 'succes' : 'erreur'); } async function resetUsb() { afficherStatut('Réinitialisation USB...', 'succes'); const r = await apiPost('/api/imprimante/reset-usb', {}); afficherStatut(r.message, r.succes ? 'succes' : 'erreur'); } async function evacuerBourrage() { const r = await apiPost('/api/imprimante/evacuer', {}); afficherStatut(r.message || 'Imprimante réactivée', r.succes ? 'succes' : 'erreur'); const el = document.getElementById('imprimante-erreur-msg'); const bloc = document.getElementById('imprimante-statut-detail'); if (r.message && r.message !== 'Imprimante réactivée') { el.textContent = '⚠ ' + r.message; bloc.style.display = 'block'; } else { bloc.style.display = 'none'; } } async function rafraichirStatutImprimante() { const r = await apiGet('/api/imprimante/statut-detail').catch(() => null); if (!r) return; const el = document.getElementById('imprimante-erreur-msg'); const bloc = document.getElementById('imprimante-statut-detail'); if (r.derniere_erreur) { let msg = r.derniere_erreur; if (msg.includes('media does not match')) msg = '⚠ Format papier incorrect — vérifiez que le format configuré correspond à la cassette chargée dans l\'imprimante'; else if (msg.includes('jam')) msg = '⚠ Bourrage papier détecté'; else msg = '⚠ ' + msg.split(']').pop().trim(); el.textContent = msg; bloc.style.display = 'block'; } else { bloc.style.display = 'none'; } } 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'), format: getValue('admin-format-papier'), copies_max: parseInt(getValue('admin-copies-max')) || 5, orientations: _getOrientations(), }, }); 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 IMPRESSION (par format) === const FORMATS_IMPRESSION = ['strip', '10x15', '15x20']; async function chargerCadresImpression() { for (const fmt of FORMATS_IMPRESSION) { await chargerCadresFormat(fmt); } } async function chargerCadresFormat(fmt) { const data = await apiGet(`/api/cadres-impression/${fmt}`); const liste = document.getElementById(`cadres-liste-${fmt}`); liste.innerHTML = ''; // Option "Aucun cadre" const divAucun = _creerItemCadreImpression(fmt, null, data.actif); liste.appendChild(divAucun); if (data.disponibles.length === 0) { const p = document.createElement('p'); p.className = 'texte-secondaire'; p.textContent = 'Aucun cadre importe'; liste.appendChild(p); return; } for (const nom of data.disponibles) { const div = _creerItemCadreImpression(fmt, nom, data.actif); liste.appendChild(div); } } function _creerItemCadreImpression(fmt, nom, actif) { const div = document.createElement('div'); div.className = 'cadre-imp-item'; const rb = document.createElement('input'); rb.type = 'radio'; rb.name = `cadre-imp-${fmt}`; rb.value = nom || ''; rb.checked = (actif === nom); rb.onchange = () => activerCadreFormat(fmt, nom); if (nom) { const img = document.createElement('img'); img.src = `/assets/cadres/${fmt}/${nom}`; img.alt = nom; img.className = 'cadre-preview'; const btnDel = document.createElement('button'); btnDel.className = 'btn-danger btn-icone'; btnDel.title = 'Supprimer'; btnDel.textContent = '✕'; btnDel.onclick = () => supprimerCadreFormat(fmt, nom); const span = document.createElement('span'); span.textContent = nom.replace('.png', ''); div.appendChild(rb); div.appendChild(img); div.appendChild(span); div.appendChild(btnDel); } else { const span = document.createElement('span'); span.textContent = 'Aucun cadre'; div.appendChild(rb); div.appendChild(span); } return div; } async function activerCadreFormat(fmt, nom) { await apiPost(`/api/cadres-impression/${fmt}/actif`, { nom: nom || null }); afficherStatut(`Cadre ${fmt} mis a jour`, 'succes'); } async function supprimerCadreFormat(fmt, nom) { await fetch(`/api/cadres-impression/${fmt}/${encodeURIComponent(nom)}`, { method: 'DELETE' }); await chargerCadresFormat(fmt); afficherStatut('Cadre supprime', 'succes'); } async function uploaderCadreFormat(fmt) { const input = document.getElementById(`input-cadre-${fmt}`); if (!input.files.length) return; const formData = new FormData(); formData.append('fichier', input.files[0]); const r = await fetch(`/api/upload/cadre/${fmt}`, { method: 'POST', body: formData }); if (r.ok) { input.value = ''; await chargerCadresFormat(fmt); afficherStatut(`Cadre ${fmt} importe`, 'succes'); } else { afficherStatut('Erreur import cadre', 'erreur'); } } // === CADRES OVERLAYS PHOTO === 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'); } // === FONDS VERTS === async function chargerFondsAdmin() { const fonds = await apiGet('/api/fonds'); const liste = document.getElementById('liste-fonds'); liste.innerHTML = ''; if (fonds.length === 0) { liste.innerHTML = 'Aucun fond importe
'; return; } for (const nom of fonds) { const div = document.createElement('div'); div.className = 'fond-item'; const img = document.createElement('img'); img.src = `/assets/backgrounds/${nom}`; img.alt = nom; const btnSuppr = document.createElement('button'); btnSuppr.className = 'btn-supprimer'; btnSuppr.innerHTML = '✕'; btnSuppr.onclick = () => supprimerFond(nom); div.appendChild(img); div.appendChild(btnSuppr); liste.appendChild(div); } } async function uploaderFond() { const input = document.getElementById('input-fond'); if (!input.files.length) return; const formData = new FormData(); formData.append('fichier', input.files[0]); await fetch('/api/upload/fond', { method: 'POST', body: formData }); input.value = ''; chargerFondsAdmin(); afficherStatut('Fond importe', 'succes'); } async function supprimerFond(nom) { if (!confirm(`Supprimer le fond "${nom}" ?`)) return; await fetch(`/api/fonds/${encodeURIComponent(nom)}`, { method: 'DELETE' }); chargerFondsAdmin(); } // === ANIMATIONS === const EMOJI_MAP = { 3: '🤪', 2: '😱', 1: '🔥' }; async function chargerAnimations() { // Animations CSS internes const anims = await apiGet('/api/animations'); const cssActives = config.camera?.animations_css_actives || ['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-item'; const cb = document.createElement('input'); cb.type = 'checkbox'; cb.checked = cssActives.includes(id); cb.dataset.animId = id; cb.onchange = () => majAnimationsCss(); const label = document.createElement('span'); label.textContent = nom; div.appendChild(cb); div.appendChild(label); liste.appendChild(div); } // Animations custom (video/GIF) await chargerAnimationsCustom(); } async function chargerAnimationsCustom() { const data = await apiGet('/api/animations/custom'); const liste = document.getElementById('liste-animations-custom'); liste.innerHTML = ''; if (data.tous.length === 0) { liste.innerHTML = 'Aucune animation importee
'; return; } for (const nom of data.tous) { const div = document.createElement('div'); div.className = 'anim-item'; const cb = document.createElement('input'); cb.type = 'checkbox'; cb.checked = data.actives.includes(nom); cb.dataset.animNom = nom; cb.onchange = () => majAnimationsCustom(); // Preview miniature const ext = nom.split('.').pop().toLowerCase(); let preview; if (ext === 'gif') { preview = document.createElement('img'); preview.src = `/assets/animations/${nom}`; preview.className = 'anim-item-preview'; } else { preview = document.createElement('video'); preview.src = `/assets/animations/${nom}`; preview.className = 'anim-item-preview'; preview.muted = true; preview.preload = 'metadata'; } const label = document.createElement('span'); label.textContent = nom; const btnSuppr = document.createElement('button'); btnSuppr.className = 'btn-supprimer'; btnSuppr.innerHTML = '✕'; btnSuppr.onclick = () => supprimerAnimation(nom); div.appendChild(cb); div.appendChild(preview); div.appendChild(label); div.appendChild(btnSuppr); liste.appendChild(div); } } async function majAnimationsCss() { const checkboxes = document.querySelectorAll('#liste-animations .anim-item input[type="checkbox"]'); const actives = []; checkboxes.forEach(cb => { if (cb.checked) actives.push(cb.dataset.animId); }); // Au moins une doit rester active if (actives.length === 0) actives.push('classique'); await apiPost('/api/config', { camera: { animations_css_actives: actives } }); } async function majAnimationsCustom() { const checkboxes = document.querySelectorAll('#liste-animations-custom .anim-item input[type="checkbox"]'); const actives = []; checkboxes.forEach(cb => { if (cb.checked) actives.push(cb.dataset.animNom); }); await apiPost('/api/animations/custom', { actives }); } async function uploaderAnimation() { const input = document.getElementById('input-animation'); if (!input.files.length) return; const formData = new FormData(); formData.append('fichier', input.files[0]); await fetch('/api/upload/animation', { method: 'POST', body: formData }); input.value = ''; chargerAnimationsCustom(); afficherStatut('Animation importee', 'succes'); } async function supprimerAnimation(nom) { if (!confirm(`Supprimer l'animation "${nom}" ?`)) return; await fetch(`/api/animations/custom/${encodeURIComponent(nom)}`, { method: 'DELETE' }); chargerAnimationsCustom(); } function testerAnimationPreview() { const chiffre = document.getElementById('preview-anim-chiffre'); const video = document.getElementById('preview-anim-video'); // Verifier s'il y a des animations custom actives const customActives = []; document.querySelectorAll('#liste-animations-custom .anim-item input[type="checkbox"]:checked').forEach(cb => { customActives.push(cb.dataset.animNom); }); // Verifier les CSS actives const cssActives = []; document.querySelectorAll('#liste-animations .anim-item input[type="checkbox"]:checked').forEach(cb => { cssActives.push(cb.dataset.animId); }); const toutes = [...cssActives.map(a => ({type: 'css', id: a})), ...customActives.map(a => ({type: 'custom', nom: a}))]; if (toutes.length === 0) return; const choix = toutes[Math.floor(Math.random() * toutes.length)]; if (choix.type === 'custom') { // Jouer la video/gif chiffre.classList.add('cache'); video.classList.remove('cache'); video.src = `/assets/animations/${choix.nom}`; video.currentTime = 0; video.play(); video.onended = () => { video.classList.add('cache'); chiffre.classList.remove('cache'); }; // Pour les GIF, masquer apres 3s if (choix.nom.endsWith('.gif')) { setTimeout(() => { video.classList.add('cache'); chiffre.classList.remove('cache'); }, 3000); } } else { // Animation CSS video.classList.add('cache'); chiffre.classList.remove('cache'); let count = 3; function afficher() { if (choix.id === 'emoji') { chiffre.textContent = EMOJI_MAP[count] || count; } else { chiffre.textContent = count; } chiffre.className = 'anim-chiffre'; void chiffre.offsetWidth; chiffre.classList.add('anim-' + choix.id); 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 === async function chargerEvenementAdmin() { const event = config.evenement || {}; document.getElementById('admin-theme').value = event.theme || 'base'; setValue('admin-nom-event', event.nom); setValue('admin-couleur-primaire', event.couleur_primaire || '#e91e63'); setValue('admin-couleur-secondaire', event.couleur_secondaire || '#ffffff'); await rafraichirMediaAccueil(); const select = document.getElementById('admin-media-accueil'); if (event.media_accueil) select.value = event.media_accueil; } function changerTheme(theme) { document.documentElement.setAttribute('data-theme', theme); } async function rafraichirMediaAccueil() { const data = await apiGet('/api/animations/custom'); const select = document.getElementById('admin-media-accueil'); const valeur = select.value; select.innerHTML = ''; for (const nom of data.tous) { const opt = document.createElement('option'); opt.value = nom; opt.textContent = nom; select.appendChild(opt); } if (valeur) select.value = valeur; } async function uploaderMediaAccueil() { const input = document.getElementById('input-media-accueil'); if (!input.files.length) return; const formData = new FormData(); formData.append('fichier', input.files[0]); await fetch('/api/upload/animation', { method: 'POST', body: formData }); input.value = ''; await rafraichirMediaAccueil(); afficherStatut('Media importe', 'succes'); } async function sauvegarderEvenement() { await apiPost('/api/config', { evenement: { theme: document.getElementById('admin-theme').value, nom: getValue('admin-nom-event'), couleur_primaire: getValue('admin-couleur-primaire'), couleur_secondaire: getValue('admin-couleur-secondaire'), media_accueil: getValue('admin-media-accueil') || null, }, }); appliquerConfig(); 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'); } function quitterNavigateur() { apiPost('/api/systeme/quitter-navigateur'); } // === 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 : ''; } // === BOOTH (Galerie Live) === async function chargerBoothAdmin() { const booth = config.booth || {}; document.getElementById('admin-booth-actif').checked = booth.actif || false; setValue('admin-booth-url', booth.url || 'https://booth.copydev.fr'); setValue('admin-booth-apikey', booth.api_key || 'booth-photobooth-2026'); setValue('admin-booth-eventid', booth.event_id || 'default'); // Recuperer le code actuel if (booth.actif && booth.url) { try { const info = await apiGet('/api/booth/info'); if (info.password) { document.getElementById('admin-booth-password').textContent = info.password; } } catch (e) { document.getElementById('admin-booth-password').textContent = '--'; } } } async function sauvegarderBooth() { await apiPost('/api/config', { booth: { actif: document.getElementById('admin-booth-actif').checked, url: getValue('admin-booth-url'), api_key: getValue('admin-booth-apikey'), event_id: getValue('admin-booth-eventid'), } }); afficherStatut('Galerie live sauvegardee', 'succes'); chargerBoothAdmin(); chargerBoothInfo(); } // === INFOS SYSTEME === async function chargerInfosSysteme() { const contenu = document.getElementById('infos-systeme-contenu'); contenu.innerHTML = 'Chargement...
'; try { const info = await apiGet('/api/systeme/info'); let html = ''; // Reseau html += 'Impossible de charger les informations systeme.
'; } } async function regenererBoothPassword() { const booth = config.booth || {}; const url = getValue('admin-booth-url').replace(/\/$/, ''); const apiKey = getValue('admin-booth-apikey'); const eventId = getValue('admin-booth-eventid') || 'default'; try { const resp = await fetch(`${url}/api/${eventId}/reset-password`, { method: 'POST', headers: { 'X-Api-Key': apiKey }, }); const data = await resp.json(); if (data.password) { document.getElementById('admin-booth-password').textContent = data.password; afficherStatut('Nouveau code genere : ' + data.password, 'succes'); } } catch (e) { afficherStatut('Erreur connexion au serveur booth', 'erreur'); } } async function chargerDiagCamera() { const el = document.getElementById('diag-camera-contenu'); el.textContent = 'Test en cours...'; try { const data = await apiGet('/api/camera/debug'); let txt = ''; for (const [k, v] of Object.entries(data)) { if (k === 'config_widgets_top') { txt += `${k}: ${Array.isArray(v) ? v.join(', ') : v}\n`; } else { txt += `${k}: ${JSON.stringify(v)}\n`; } } el.textContent = txt || 'Aucune donnee'; } catch (e) { el.textContent = 'ERREUR : ' + e.message; } }