COLLECTOR ACCOUNT
<!DOCTYPE html> <html lang="fr"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>VX — Compte & Collector</title> <style> body { margin: 0; font-family: Arial, sans-serif; background: #080b12; color: white; } .vx-container { width: min(900px, 92%); margin: 40px auto; } .vx-panel { background: #111827; border: 1px solid #263043; border-radius: 20px; padding: 25px; margin-bottom: 20px; } input, button { box-sizing: border-box; border-radius: 10px; padding: 12px; border: 0; } input { width: 100%; margin: 6px 0; background: #1f2937; color: white; } button { cursor: pointer; font-weight: bold; } .vx-button { width: 100%; margin-top: 10px; color: white; background: linear-gradient(135deg,#2563eb,#7c3aed); } .vx-button:hover { transform: translateY(-1px); } .vx-balance { font-size: 25px; font-weight: bold; } .vx-status { color: #9ca3af; } .vx-status.ok { color: #22c55e; } .vx-status.no { color: #ef4444; } /* COLLECTION */ .collector-grid { display: grid; grid-template-columns: repeat(auto-fit,minmax(180px,1fr)); gap: 15px; } .collector-card { text-align: center; padding: 20px; border-radius: 18px; background: #0f172a; border: 1px solid #293548; } .collector-logo { width: 90px; height: 90px; margin: auto; display: flex; align-items: center; justify-content: center; border-radius: 50%; font-size: 25px; font-weight: bold; background: linear-gradient( 135deg, #a855f7, #2563eb ); } .collector-card button { margin-top: 10px; width: 100%; color: white; background: #2563eb; } .collector-card button:disabled { background: #374151; cursor: not-allowed; } .small { font-size: 13px; color: #9ca3af; } </style> </head> <body> <div class="vx-container"> <!-- ========================== COMPTE ========================== --> <section class="vx-panel"> <h1>Compte VX</h1> <input id="username" type="text" placeholder="Nom d'utilisateur" autocomplete="username" > <input id="email" type="email" placeholder="Adresse e-mail" autocomplete="email" > <button class="vx-button" onclick="createAccount()" > CRÉER MON COMPTE </button> <p id="accountMessage" class="vx-status"> </p> </section> <!-- ========================== STATUT ========================== --> <section class="vx-panel"> <h2>Statut du compte</h2> <p> Utilisateur : <strong id="displayUsername">—</strong> </p> <p> Statut 18+ : <strong id="ageStatus" class="vx-status no"> Non vérifié </strong> </p> <p> Monnaie VX : </p> <div class="vx-balance"> <span id="vxBalance">0</span> VX </div> </section> <!-- ========================== VÉRIFICATION ========================== --> <section class="vx-panel"> <h2>Vérification d'âge</h2> <p class="small"> Cette démonstration ne collecte aucune pièce d'identité ni donnée biométrique. </p> <button class="vx-button" onclick="setAgeVerified()" > CONFIRMER LA VÉRIFICATION 18+ </button> </section> <!-- ========================== COLLECTOR ========================== --> <section class="vx-panel"> <h2>✦ COLLECTOR</h2> <p class="small"> Échange tes VX contre des Xenodis. </p> <div id="collectorGrid" class="collector-grid"> </div> </section> </div> <script> /* ===================================================== CONFIGURATION ===================================================== */ const VX_STORAGE = "vx_user_account_v1"; /* ===================================================== CATALOGUE XENODIS ===================================================== */ const XENODIS = [ { id: "origin", name: "Xenodis Origin", price: 100, logo: "VX" }, { id: "nova", name: "Xenodis Nova", price: 500, logo: "✦" }, { id: "eclipse", name: "Xenodis Eclipse", price: 1500, logo: "◈" }, { id: "prime", name: "Xenodis Prime", price: 5000, logo: "VX+" }, { id: "infinity", name: "Xenodis Infinity", price: 15000, logo: "∞" }, { id: "one", name: "Xenodis One", price: 50000, logo: "Ⅰ" } ]; /* ===================================================== COMPTE PAR DÉFAUT ===================================================== */ function defaultUser() { return { id: null, username: null, email: null, ageVerified: false, vx: 0, collector: [] }; } /* ===================================================== CHARGER LE COMPTE ===================================================== */ function loadUser() { try { const saved = localStorage.getItem(VX_STORAGE); if (!saved) { return defaultUser(); } return { ...defaultUser(), ...JSON.parse(saved) }; } catch { return defaultUser(); } } let user = loadUser(); /* ===================================================== SAUVEGARDE ===================================================== */ function saveUser() { localStorage.setItem( VX_STORAGE, JSON.stringify(user) ); } /* ===================================================== CRÉATION DU COMPTE ===================================================== */ function createAccount() { const username = document .getElementById("username") .value .trim(); const email = document .getElementById("email") .value .trim(); if (!username || !email) { showMessage( "Complète les informations du compte.", true ); return; } if (!user.id) { user.id = crypto.randomUUID(); } user.username = username; user.email = email; saveUser(); updateInterface(); showMessage( "Compte créé avec succès." ); } /* ===================================================== VÉRIFICATION 18+ ===================================================== */ /* Dans un vrai site, cette valeur devrait provenir d'un processus de vérification fiable côté serveur. Le navigateur ne doit pas décider lui-même qu'une personne est majeure à partir d'une photo. */ function setAgeVerified() { user.ageVerified = true; saveUser(); updateInterface(); showMessage( "Statut 18+ enregistré." ); } /* ===================================================== AJOUTER DES VX ===================================================== */ /* Démonstration uniquement. Sur un vrai site, le solde doit être crédité côté serveur après une opération autorisée. */ function addVX(amount) { if (!Number.isFinite(amount) || amount <= 0) { return; } user.vx += amount; saveUser(); updateInterface(); } /* ===================================================== ACHAT XENODIS ===================================================== */ function buyXenodis(id) { if (!user.id) { alert( "Crée d'abord ton compte." ); return; } /* Protection d'accès : les échanges Collector nécessitent ici un statut 18+ vérifié. */ if (!user.ageVerified) { alert( "La vérification 18+ est nécessaire." ); return; } const item = XENODIS.find( x => x.id === id ); if (!item) { return; } if (user.collector.includes(id)) { alert( "Ce Xenodis est déjà dans ta collection." ); return; } if (user.vx < item.price) { alert( "Solde VX insuffisant." ); return; } /* ÉCHANGE */ user.vx -= item.price; user.collector.push(id); saveUser(); updateInterface(); alert( item.name + " ajouté à ta collection !" ); } /* ===================================================== AFFICHAGE COLLECTOR ===================================================== */ function renderCollector() { const grid = document.getElementById( "collectorGrid" ); grid.innerHTML = ""; XENODIS.forEach(item => { const owned = user.collector.includes( item.id ); const card = document.createElement( "article" ); card.className = "collector-card"; card.innerHTML = ` <div class="collector-logo"> ${item.logo} </div> <h3> ${item.name} </h3> <p> ${item.price.toLocaleString()} VX </p> <button ${owned ? "disabled" : ""} onclick="buyXenodis('${item.id}')" > ${ owned ? "✓ COLLECTIONNÉ" : "ÉCHANGER" } </button> `; grid.appendChild(card); }); } /* ===================================================== INTERFACE ===================================================== */ function updateInterface() { document .getElementById( "displayUsername" ) .textContent = user.username || "—"; document .getElementById( "vxBalance" ) .textContent = user.vx.toLocaleString(); const age = document.getElementById( "ageStatus" ); if (user.ageVerified) { age.textContent = "✓ 18+ vérifié"; age.className = "vx-status ok"; } else { age.textContent = "Non vérifié"; age.className = "vx-status no"; } renderCollector(); } /* ===================================================== MESSAGE ===================================================== */ function showMessage( message, error = false ) { const element = document.getElementById( "accountMessage" ); element.textContent = message; element.className = error ? "vx-status no" : "vx-status ok"; } /* ===================================================== INITIALISATION ===================================================== */ updateInterface(); </script> </body> </html>
AVEC CERTIFICATION COLLECTOR ACCOUNT
Et côté interface, tu peux afficher les trois confirmations ainsi :
PROMOTION XENO 30% ACTIF