from pathlib import Path
import base64, json, os, sys
img_path = Path("/mnt/data/d963e04e-f5cd-4e67-a88e-4818770e2656.png")
if img_path.exists():
b = img_path.read_bytes()
data_uri = "data:image/png;base64," + base64.b64encode(b).decode('ascii')
else:
data_uri = ""
html_template = """
<title>ALPAC+ – Programme de Fidélité</title>
<style>
:root{--grad:linear-gradient(90deg,#ff004c,#ff7a00,#ffe600,#00c94d,#0084ff,#7a00ff);--card:#1a1a1a;--bg:#000}
*{box-sizing:border-box}
body{margin:0;font-family:Inter,Arial,Helvetica,sans-serif;background:var(--bg);color:#fff}
.header{display:flex;align-items:center;gap:16px;justify-content:center;padding:20px;border-bottom:6px solid transparent;border-image:var(--grad) 1}
.logo{height:64px;width:64px;border-radius:12px;box-shadow:0 6px 20px rgba(0,0,0,0.6)}
h1{margin:0;font-size:20px}
nav{background:
#111;padding:12px;display:flex;justify-content:center;gap:24px;border-bottom:4px solid transparent;border-image:var(--grad) 1}
nav a{color:#fff;text-decoration:none;font-weight:700}
.container{max-width:1100px;margin:28px auto;padding:0 20px}
.hero{background:
#111;padding:32px;text-align:center;border-top:4px solid transparent;border-image:var(--grad) 1}
.points-box{display:inline-block;background:#000;padding:14px;border-radius:10px;border:3px solid transparent;border-image:var(--grad) 1;font-weight:700}
.progress-wrap{max-width:700px;margin:18px auto}
.progress-bar-outer{background:
#222;border-radius:12px;overflow:hidden;border:2px solid #fff;height:30px}
.progress-bar-inner{height:100%;width:0;background:var(--grad);color:#000;display:flex;align-items:center;justify-content:center;font-weight:700}
.section{padding:28px 0}
.card-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:16px}
.card{background:var(--card);padding:16px;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.4)}
button.primary{background:var(--grad);border:none;color:#fff;padding:10px 14px;border-radius:10px;cursor:pointer;font-weight:700}
.small{padding:8px 10px;font-size:14px;border-radius:8px}
.profile-card{display:flex;flex-direction:column;align-items:center;gap:8px}
#profilePhoto{width:120px;height:120px;border-radius:50%;object-fit:cover;border:4px solid #ff004c}
.footer{text-align:center;padding:24px;margin-top:24px;border-top:1px solid rgba(255,255,255,0.03)}
.modal{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.75);align-items:center;justify-content:center;z-index:9999}
.modal .box{background:
#111;padding:18px;border-radius:12px;border:3px solid #ff004c;max-width:420px;width:90%}
.input{width:100%;padding:10px;border-radius:8px;margin-top:10px;border:none;background:
#222;color:#fff}
.mission-proof{display:flex;gap:8px;align-items:center}
.history-list{max-height:160px;overflow:auto;margin-top:10px;padding:8px;background:#0f0f0f;border-radius:8px}
.notice{background:#081b0f;padding:10px;border-radius:8px;border:1px solid rgba(255,255,255,0.03);margin-top:10px}
</style>

ALPAC+ – Programme de Fidélité
Gagne des points et débloque des récompenses
Tableau de bord
Récompenses
Missions
Mon compte
Bienvenue 🎉
Points : 0 pts
Niveau : Bronze
🔥 Missions
<div style="margin-top:16px">
<h4>Historique des missions validées</h4>
<div id="history" class="history-list">Aucune mission validée pour l'instant.</div>
</div>
👤 Mon compte
Non connecté
-
Se déconnecter
S'inscrire / Se connecter
© 2025 ALPAC+ – Tous droits réservés
Créer un compte / Se connecter
S'inscrire
Se connecter
Fermer
Valider mission
Envoyer preuve
Annuler
Envoie une photo ou ticket prouvant la mission.
<script>
const API = (function(){
function delay(ms){return new Promise(r=>setTimeout(r,ms))}
return {
register: async (data) => { await delay(400); localStorage.setItem('alpac_user', JSON.stringify({name:data.name,email:data.email,points:0})); return {ok:true} },
login: async (data) => { await delay(300); const u = JSON.parse(localStorage.getItem('alpac_user')||'null'); if(u && u.email===data.email) return {ok:true,user:u}; return {ok:false,error:'Utilisateur non trouvé'} },
getUser: async () => { await delay(120); return JSON.parse(localStorage.getItem('alpac_user')||'null') },
addPoints: async (pts) => { await delay(250); const u = JSON.parse(localStorage.getItem('alpac_user')||'null')||{points:0}; u.points = (u.points||0)+pts; localStorage.setItem('alpac_user', JSON.stringify(u)); return {points:u.points} },
setPhoto: async (dataUrl) => { await delay(120); const u = JSON.parse(localStorage.getItem('alpac_user')||'null')||{}; u.photo = dataUrl; localStorage.setItem('alpac_user', JSON.stringify(u)); return {ok:true} },
getMissions: async () => { await delay(100); return [
{key:'achat_mois',title:'Achat du mois',points:20},
{key:'parrainage',title:'Parrainage',points:50},
{key:'challenge_5j',title:'Connexion 5 jours',points:15}
]},
validateMission: async (missionKey, proofDataUrl) => { await delay(500);
if(!proofDataUrl || proofDataUrl.length<1000) return {ok:false,error:'Preuve invalide'};
const history = JSON.parse(localStorage.getItem('alpac_history')||'[]');
if(history.find(h=>h.missionKey===missionKey)) return {ok:false,error:'Mission déjà validée'};
const missions = await API.getMissions();
const m = missions.find(x=>x.key===missionKey);
if(!m) return {ok:false,error:'Mission introuvable'};
history.push({missionKey, title:m.title, points:m.points, date:new Date().toISOString()});
localStorage.setItem('alpac_history', JSON.stringify(history));
const res = await API.addPoints(m.points);
return {ok:true,points:res.points,added:m.points};
},
getHistory: async ()=>{ await delay(80); return JSON.parse(localStorage.getItem('alpac_history')||'[]') }
}
})();
const NEXT_REWARD = 300;
let currentMissionKey = null;
async function init(){
document.getElementById('btnOpenRegister').addEventListener('click', ()=>openModal('modalRegister'));
document.getElementById('uploadPhoto').addEventListener('change', handleProfileUpload);
document.getElementById('btnLogout').addEventListener('click', logout);
await renderMissions();
await refreshProfile();
}
function openModal(id){ document.getElementById(id).style.display='flex'; document.getElementById(id).setAttribute('aria-hidden','false') }
function closeModal(id){ document.getElementById(id).style.display='none'; document.getElementById(id).setAttribute('aria-hidden','true') }
async function doRegister(){
const name = document.getElementById('regName').value.trim();
const email = document.getElementById('regEmail').value.trim();
if(!name || !email) return alert('Remplis nom et email');
await API.register({name,email});
alert('Inscription OK — connecté');
closeModal('modalRegister');
await refreshProfile();
}
async function doLogin(){
const email = document.getElementById('regEmail').value.trim();
if(!email) return alert('Donne ton email');
const r = await API.login({email});
if(!r.ok) return alert(r.error||'Erreur');
alert('Connecté');
closeModal('modalRegister');
await refreshProfile();
}
async function refreshProfile(){
const u = await API.getUser();
if(u){
document.getElementById('profileName').textContent = u.name || '—';
document.getElementById('profileEmail').textContent = u.email || '-';
document.getElementById('btnLogout').style.display = 'inline-block';
if(u.photo) document.getElementById('profilePhoto').src = u.photo;
document.getElementById('pointsDisplay').textContent = (u.points||0);
updateProgress(u.points||0);
renderHistory();
} else {
document.getElementById('profileName').textContent = 'Non connecté';
document.getElementById('profileEmail').textContent = '-';
document.getElementById('btnLogout').style.display = 'none';
document.getElementById('profilePhoto').src = '';
document.getElementById('pointsDisplay').textContent = '0';
updateProgress(0);
}
}
async function renderMissions(){
const grid = document.getElementById('missionsGrid');
grid.innerHTML = '';
const missions = await API.getMissions();
missions.forEach(m=>{
const div = document.createElement('div');
div.className = 'card';
div.innerHTML = `
${m.title}
+${m.points} pts
Valider
`;
grid.appendChild(div);
});
}
function openMission(key,title,points){
currentMissionKey = key;
document.getElementById('missionTitle').textContent = `Valider : ${title} (+${points} pts)`;
openModal('modalMission');
}
async function submitMission(){
const fi = document.getElementById('missionProof');
if(!fi.files.length) return alert('Ajoute une photo comme preuve');
const file = fi.files[0];
const reader = new FileReader();
reader.onload = async function(e){
const dataUrl = e.target.result;
const res = await API.validateMission(currentMissionKey,dataUrl);
if(!res.ok){
alert(res.error || 'Preuve non acceptée');
return;
}
alert(`Mission validée ! +${res.added} pts`);
closeModal('modalMission');
document.getElementById('missionProof').value = '';
await refreshProfile();
await renderMissions();
};
reader.readAsDataURL(file);
}
async function renderHistory(){
const history = await API.getHistory();
const el = document.getElementById('history');
if(!history.length){ el.innerHTML = "Aucune mission validée pour l'instant."; return; }
el.innerHTML = history.map(h=>`
${h.title} — +${h.points} pts
${new Date(h.date).toLocaleString()}
`).join('');
}
function handleProfileUpload(e){
const f = e.target.files[0];
if(!f) return;
const r = new FileReader();
r.onload = async function(ev){
const url = ev.target.result;
document.getElementById('profilePhoto').src = url;
await API.setPhoto(url);
alert('Photo de profil mise à jour');
};
r.readAsDataURL(f);
}
function logout(){
localStorage.removeItem('alpac_user');
localStorage.removeItem('alpac_history');
alert('Déconnecté');
refreshProfile();
}
function updateProgress(points){
const p = points||0;
const percent = Math.min(Math.round((p / NEXT_REWARD) * 100),100);
const bar = document.getElementById('progressBar');
bar.style.width = percent + '%';
bar.textContent = percent + '%';
const levelLabel = document.getElementById('levelLabel');
if(p >= 1000) levelLabel.textContent = 'Niveau : Platine';
else if(p >= 500) levelLabel.textContent = 'Niveau : Or';
else if(p >= 300) levelLabel.textContent = 'Niveau : Argent';
else levelLabel.textContent = 'Niveau : Bronze';
}
init();
</script>
"""
html_content = html_template.replace("{DATA_URI}", data_uri)
out_path = "/mnt/data/alpac-plus.html"
with open(out_path, "w", encoding="utf-8") as f:
f.write(html_content)
out_path
from pathlib import Path
import base64, json, os, sys
img_path = Path("/mnt/data/d963e04e-f5cd-4e67-a88e-4818770e2656.png")
if img_path.exists():
b = img_path.read_bytes()
data_uri = "data:image/png;base64," + base64.b64encode(b).decode('ascii')
else:
data_uri = ""
html_template = """
<title>ALPAC+ – Programme de Fidélité</title> <style> :root{--grad:linear-gradient(90deg,#ff004c,#ff7a00,#ffe600,#00c94d,#0084ff,#7a00ff);--card:#1a1a1a;--bg:#000} *{box-sizing:border-box} body{margin:0;font-family:Inter,Arial,Helvetica,sans-serif;background:var(--bg);color:#fff} .header{display:flex;align-items:center;gap:16px;justify-content:center;padding:20px;border-bottom:6px solid transparent;border-image:var(--grad) 1} .logo{height:64px;width:64px;border-radius:12px;box-shadow:0 6px 20px rgba(0,0,0,0.6)} h1{margin:0;font-size:20px} nav{background:#111;padding:12px;display:flex;justify-content:center;gap:24px;border-bottom:4px solid transparent;border-image:var(--grad) 1} nav a{color:#fff;text-decoration:none;font-weight:700} .container{max-width:1100px;margin:28px auto;padding:0 20px} .hero{background:#111;padding:32px;text-align:center;border-top:4px solid transparent;border-image:var(--grad) 1} .points-box{display:inline-block;background:#000;padding:14px;border-radius:10px;border:3px solid transparent;border-image:var(--grad) 1;font-weight:700} .progress-wrap{max-width:700px;margin:18px auto} .progress-bar-outer{background:#222;border-radius:12px;overflow:hidden;border:2px solid #fff;height:30px} .progress-bar-inner{height:100%;width:0;background:var(--grad);color:#000;display:flex;align-items:center;justify-content:center;font-weight:700} .section{padding:28px 0} .card-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:16px} .card{background:var(--card);padding:16px;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,0.4)} button.primary{background:var(--grad);border:none;color:#fff;padding:10px 14px;border-radius:10px;cursor:pointer;font-weight:700} .small{padding:8px 10px;font-size:14px;border-radius:8px} .profile-card{display:flex;flex-direction:column;align-items:center;gap:8px} #profilePhoto{width:120px;height:120px;border-radius:50%;object-fit:cover;border:4px solid #ff004c} .footer{text-align:center;padding:24px;margin-top:24px;border-top:1px solid rgba(255,255,255,0.03)} .modal{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.75);align-items:center;justify-content:center;z-index:9999} .modal .box{background:#111;padding:18px;border-radius:12px;border:3px solid #ff004c;max-width:420px;width:90%} .input{width:100%;padding:10px;border-radius:8px;margin-top:10px;border:none;background:#222;color:#fff} .mission-proof{display:flex;gap:8px;align-items:center} .history-list{max-height:160px;overflow:auto;margin-top:10px;padding:8px;background:#0f0f0f;border-radius:8px} .notice{background:#081b0f;padding:10px;border-radius:8px;border:1px solid rgba(255,255,255,0.03);margin-top:10px} </style>ALPAC+ – Programme de Fidélité
Bienvenue 🎉
🎁 Récompenses
10% réduction
300 pts
Accès VIP 24h
500 pts
Cadeau exclusif
750 pts
🔥 Missions
👤 Mon compte
-
Créer un compte / Se connecter
Valider mission
${m.title}
+${m.points} pts
${new Date(h.date).toLocaleString()}
html_content = html_template.replace("{DATA_URI}", data_uri)
out_path = "/mnt/data/alpac-plus.html"
with open(out_path, "w", encoding="utf-8") as f:
f.write(html_content)
out_path