diff --git a/backend/mailer.py b/backend/mailer.py index 204f050..fa62448 100644 --- a/backend/mailer.py +++ b/backend/mailer.py @@ -1,3 +1,4 @@ +import json import logging import smtplib from email.mime.base import MIMEBase @@ -6,7 +7,7 @@ from email.mime.text import MIMEText from email import encoders from pathlib import Path -from backend.config import charger_config +from backend.config import charger_config, RACINE log = logging.getLogger("photobooth.mailer") @@ -58,7 +59,38 @@ def envoyer_photo(destinataire: str, chemin_photo: Path) -> bool: serveur.login(smtp_user, smtp_password) serveur.send_message(msg) log.info(f"Email envoye a {destinataire}") + _sauvegarder_email_historique(destinataire) return True except (smtplib.SMTPException, OSError) as e: log.error(f"Erreur envoi email : {e}") return False + + +FICHIER_EMAILS = RACINE / "data" / "emails_history.json" + + +def _sauvegarder_email_historique(email: str): + historique = charger_emails_historique() + email_lower = email.lower().strip() + if email_lower not in historique: + historique.append(email_lower) + try: + with open(FICHIER_EMAILS, "w", encoding="utf-8") as f: + json.dump(historique, f, ensure_ascii=False) + except OSError: + pass + + +def charger_emails_historique() -> list: + if not FICHIER_EMAILS.exists(): + return [] + try: + with open(FICHIER_EMAILS, "r", encoding="utf-8") as f: + return json.load(f) + except (json.JSONDecodeError, OSError): + return [] + + +def effacer_emails_historique(): + if FICHIER_EMAILS.exists(): + FICHIER_EMAILS.unlink() diff --git a/backend/main.py b/backend/main.py index d1597de..f602665 100644 --- a/backend/main.py +++ b/backend/main.py @@ -28,7 +28,7 @@ from backend.effects import appliquer_filtre, appliquer_overlay, chroma_key, lis from backend.collage import creer_strip, creer_collage from backend.destinations import distribuer_photo, detecter_usb, compteur_restant, reset_compteur, recuperer_booth_password from backend.printer import lister_imprimantes, imprimer -from backend.mailer import envoyer_photo +from backend.mailer import envoyer_photo, charger_emails_historique, effacer_emails_historique from backend.qrcode_gen import generer_qr, qr_galerie logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(name)s] %(message)s") @@ -777,6 +777,17 @@ async def api_email(donnees: dict): return {"succes": ok} +@app.get("/api/emails/historique") +async def api_emails_historique(): + return {"emails": charger_emails_historique()} + + +@app.delete("/api/emails/historique") +async def api_emails_historique_supprimer(): + effacer_emails_historique() + return {"succes": True} + + # --- API QR Code --- @app.get("/api/qr") diff --git a/frontend/css/style.css b/frontend/css/style.css index 6e4e4fd..2b2f047 100644 --- a/frontend/css/style.css +++ b/frontend/css/style.css @@ -674,10 +674,16 @@ html, body { } .form-email { + position: fixed; + inset: 0; + z-index: 200; + background: var(--fond); display: flex; - gap: 0.8rem; + flex-direction: column; align-items: center; - margin: 1rem 0; + justify-content: center; + gap: 0.5rem; + padding: 1rem; } .form-email input { @@ -686,8 +692,9 @@ html, body { border-radius: 12px; padding: 0.8rem 1.2rem; color: var(--texte); - font-size: 1.1rem; - width: 300px; + font-size: 1.2rem; + width: min(90vw, 500px); + text-align: center; outline: none; } @@ -695,6 +702,30 @@ html, body { border-color: var(--primaire); } +.email-suggestions { + display: flex; + flex-wrap: wrap; + gap: 0.4rem; + justify-content: center; + max-width: 90vw; + max-height: 4.5rem; + overflow-y: auto; +} + +.email-suggestions button { + background: rgba(255,255,255,0.08); + border: 1px solid rgba(255,255,255,0.15); + border-radius: 20px; + color: var(--texte); + padding: 0.3rem 0.8rem; + font-size: 0.85rem; + cursor: pointer; +} + +.email-suggestions button:active { + background: var(--primaire); +} + .zone-qr { margin: 1rem 0; } diff --git a/frontend/index.html b/frontend/index.html index 8851f7f..a43404d 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -157,6 +157,7 @@
+
diff --git a/frontend/js/share.js b/frontend/js/share.js index af72ef4..74976ac 100644 --- a/frontend/js/share.js +++ b/frontend/js/share.js @@ -89,9 +89,10 @@ async function lancerImpression() { } } -function ouvrirEmail() { +async function ouvrirEmail() { document.getElementById('form-email').classList.remove('cache'); document.getElementById('input-email').value = ''; + await chargerSuggestionsEmail(); } function fermerEmail() { @@ -99,14 +100,39 @@ function fermerEmail() { document.getElementById('input-email').value = ''; } +async function chargerSuggestionsEmail() { + const container = document.getElementById('email-suggestions'); + container.innerHTML = ''; + const data = await apiGet('/api/emails/historique').catch(() => null); + if (!data || !data.emails || data.emails.length === 0) return; + for (const email of data.emails) { + const btn = document.createElement('button'); + btn.textContent = email; + btn.onclick = () => { + document.getElementById('input-email').value = email; + }; + container.appendChild(btn); + } +} + function clavierTape(car) { const input = document.getElementById('input-email'); input.value += car; + filtrerSuggestionsEmail(); } function clavierEffacer() { const input = document.getElementById('input-email'); input.value = input.value.slice(0, -1); + filtrerSuggestionsEmail(); +} + +function filtrerSuggestionsEmail() { + const val = document.getElementById('input-email').value.toLowerCase(); + const btns = document.querySelectorAll('#email-suggestions button'); + btns.forEach(btn => { + btn.style.display = (!val || btn.textContent.includes(val)) ? '' : 'none'; + }); } async function envoyerEmail() {