--- /dev/null
+<!DOCTYPE html>
+<html lang="fr">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>Portefeuille Bitcoin</title>
+
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet">
+ <link rel="stylesheet" href="styles.css">
+
+ <script type="importmap">
+{
+ "imports": {
+ "socket.io-client": "https://cdn.socket.io/4.7.5/socket.io.esm.min.js"
+ }
+}
+</script>
+<script type="module" src="script.js"></script>
+
+</head>
+<body>
+
+<div class="main-content">
+<div class="container py-5">
+
+ <h1 class="text-center mb-4">
+ <i class="bi bi-currency-bitcoin text-warning"></i>
+ Portefeuille Bitcoin
+ </h1>
+
+ <!-- Choix crypto + adresse -->
+ <div class="card p-4 mb-4">
+ <div class="mb-3">
+ <label class="form-label">Choisir une cryptomonnaie</label>
+ <select class="form-select">
+ <option>Bitcoin (BTC)</option>
+ <option>Ethereum (ETH)</option>
+ <option>Litecoin (LTC)</option>
+ </select>
+ </div>
+
+ <div class="mb-3">
+ <label class="form-label">Adresse du portefeuille</label>
+ <input type="text" class="form-control" placeholder="Entrez une adresse crypto">
+ </div>
+
+ <button class="btn btn-warning">
+ <i class="bi bi-wallet2"></i> Voir le portefeuille
+ </button>
+ </div>
+
+ <!-- Cartes principales -->
+ <div class="row g-4 mb-4">
+ <div class="col-md-6">
+ <div class="card p-4 text-center">
+ <h5>Solde</h5>
+ <div class="value" id="balance">0.00000000 BTC</div>
+ </div>
+ </div>
+
+ <div class="col-md-6">
+ <div class="card p-4 text-center">
+ <h5>Prix</h5>
+ <div class="value" id="price">$0.00</div>
+ </div>
+ </div>
+ </div>
+
+ <!-- Signal complet -->
+ <div class="card p-4 mb-4">
+ <h5 class="text-center mb-3">Signal du marché</h5>
+
+ <div class="signal-box hold" id="signalBox">
+ <div class="value" id="signalAction">HOLD</div>
+ <div>Criticalité : <span id="signalCriticality">INFO</span></div>
+ <div>Confiance : <span id="signalConfidence">0%</span></div>
+ <div class="mt-2 text-secondary" id="signalReason">
+ Aucune donnée pour le moment
+ </div>
+ </div>
+ </div>
+
+ <!-- Stratégie -->
+ <div class="card p-4 mb-4">
+ <h5>Stratégie</h5>
+ <select class="form-select mb-3" id="strategySelect">
+ <option value="hold">Always HOLD</option>
+ <option value="ma_cross">MA Cross</option>
+ </select>
+ <button class="btn btn-primary">
+ Appliquer la stratégie
+ </button>
+ </div>
+
+ <!-- Actions -->
+ <div class="d-flex gap-3 mb-4">
+ <button class="btn btn-success flex-fill">
+ <i class="bi bi-cart-plus"></i> Acheter
+ </button>
+ <button class="btn btn-danger flex-fill">
+ <i class="bi bi-cash-stack"></i> Vendre
+ </button>
+ </div>
+
+ <!-- Wallets -->
+ <div class="card p-4 mb-4">
+ <h5>Wallets</h5>
+ <ul id="walletList" class="list-group list-group-flush">
+ <li class="list-group-item bg-transparent text-white">
+ Aucun wallet chargé
+ </li>
+ </ul>
+ </div>
+
+ <!-- Historique des transactions -->
+ <div class="card p-4 mb-4">
+ <h5>Historique des transactions</h5>
+ <ul id="walletEvents" class="list-group list-group-flush">
+ <li class="list-group-item bg-transparent text-white">
+ Aucune transaction
+ </li>
+ </ul>
+ </div>
+
+ <!-- Alertes -->
+ <div class="card p-4 mb-4">
+ <h5>Alertes</h5>
+ <ul id="alertList" class="list-group list-group-flush">
+ <li class="list-group-item bg-transparent text-white">
+ Aucune alerte
+ </li>
+ </ul>
+ </div>
+
+ <!-- Graphique historique -->
+ <div class="card p-4 text-center">
+ <h5>Historique des prix</h5>
+ <div class="text-light" style="height:200px; display:flex; align-items:center; justify-content:center;">
+ (Graphique historique à venir)
+ </div>
+ </div>
+
+</div>
+</div>
+
+<!-- Footer -->
+<footer class="bg-dark text-white text-center py-3 mt-5" style="width:100%;">
+ <p>Portefeuille bitcoins</p>
+ <p class="mb-0">2026 - Copyright © Tous droits réservés.</p>
+</footer>
+
+</body>
+</html>
--- /dev/null
+// script.js (module)
+import {
+ connectToAlerts,
+ onAlert,
+ disconnectFromAlerts,
+ isConnected
+} from './socketService.js';
+
+// Exemple : récupérer un userId (ici exemple statique, adapte-toi)
+const userId = 'user-123';
+
+// Connecter automatiquement à l'ouverture
+connectToAlerts(userId);
+
+// Quand une alerte arrive, l'ajouter dans la liste #alertList
+onAlert(function(alert) {
+ console.log('Nouvelle alerte reçue dans main.js :', alert);
+
+ const list = document.getElementById('alertList');
+ if (!list) return;
+
+ const li = document.createElement('li');
+ li.className = 'list-group-item bg-transparent text-white';
+ // Si l'alerte est un objet, essaye d'afficher message et type
+ if (typeof alert === 'object') {
+ li.textContent = (alert.message ? alert.message : JSON.stringify(alert));
+ } else {
+ li.textContent = String(alert);
+ }
+
+ // Préfixer pour voir les nouvelles alertes en haut
+ list.prepend(li);
+});
+
+// Déconnexion propre à la fermeture de la page
+window.addEventListener('beforeunload', () => {
+ if (isConnected()) {
+ disconnectFromAlerts();
+ }
+});
+
+// Exposer pour debug dans console
+window._alertsService = { connectToAlerts, disconnectFromAlerts, isConnected };
\ No newline at end of file
--- /dev/null
+// ═══════════════════════════════════════════════════════════
+// FICHIER : socketService.js
+// RÔLE : Gérer la connexion temps réel avec le serveur
+// CRÉÉ PAR : Stéphane (module alertes)
+// POUR : Océane (frontend web)
+// ═══════════════════════════════════════════════════════════
+
+// On importe la librairie Socket.IO
+import { io } from 'socket.io-client';
+
+// ───────────────────────────────────────────────────────────
+// CONFIGURATION
+// ───────────────────────────────────────────────────────────
+
+// L'adresse du serveur (à changer selon l'environnement)
+// En développement : localhost
+// En production : l'adresse du vrai serveur
+const SERVER_URL = 'http://localhost:3000';
+
+// ───────────────────────────────────────────────────────────
+// VARIABLES
+// ───────────────────────────────────────────────────────────
+
+// La connexion socket (null = pas encore connecté)
+let socket = null;
+
+// Liste des fonctions à appeler quand on reçoit une alerte
+let alertCallbacks = [];
+
+// ───────────────────────────────────────────────────────────
+// FONCTION : Se connecter au serveur
+// ───────────────────────────────────────────────────────────
+// Appelle cette fonction quand l'utilisateur se connecte à ton site
+//
+// Paramètre : userId = l'identifiant de l'utilisateur connecté
+//
+// Exemple : connectToAlerts('user-123');
+// ───────────────────────────────────────────────────────────
+export function connectToAlerts(userId) {
+
+ // Si déjà connecté, on ne fait rien
+ if (socket !== null) {
+ console.log('⚠️ Déjà connecté au serveur d\'alertes');
+ return;
+ }
+
+ // Créer la connexion
+ socket = io(SERVER_URL);
+
+ // ─────────────────────────────────────────────────────
+ // ÉVÉNEMENT : Connexion réussie
+ // ─────────────────────────────────────────────────────
+ socket.on('connect', function() {
+ console.log('✅ Connecté au serveur d\'alertes');
+
+ // IMPORTANT : On envoie notre userId au serveur
+ // Pour qu'il sache qui on est et nous envoie NOS alertes
+ socket.emit('auth', userId);
+ });
+
+ // ─────────────────────────────────────────────────────
+ // ÉVÉNEMENT : Authentification confirmée
+ // ─────────────────────────────────────────────────────
+ socket.on('auth_success', function(data) {
+ console.log('✅ Authentifié :', data.message);
+ });
+
+ // ─────────────────────────────────────────────────────
+ // ÉVÉNEMENT : Réception d'une alerte !
+ // ─────────────────────────────────────────────────────
+ socket.on('alert', function(alert) {
+ console.log('🔔 ALERTE REÇUE :', alert);
+
+ // On appelle toutes les fonctions enregistrées
+ // (voir onAlert plus bas)
+ alertCallbacks.forEach(function(callback) {
+ callback(alert);
+ });
+ });
+
+ // ─────────────────────────────────────────────────────
+ // ÉVÉNEMENT : Déconnexion
+ // ─────────────────────────────────────────────────────
+ socket.on('disconnect', function(reason) {
+ console.log('❌ Déconnecté du serveur :', reason);
+ });
+
+ // ─────────────────────────────────────────────────────
+ // ÉVÉNEMENT : Erreur de connexion
+ // ─────────────────────────────────────────────────────
+ socket.on('connect_error', function(error) {
+ console.log('❌ Erreur de connexion :', error.message);
+ });
+}
+
+// ───────────────────────────────────────────────────────────
+// FONCTION : S'abonner aux alertes
+// ───────────────────────────────────────────────────────────
+// Appelle cette fonction pour dire "quand il y a une alerte,
+// exécute cette fonction"
+//
+// Paramètre : callback = la fonction à exécuter
+//
+// Exemple :
+// onAlert(function(alert) {
+// console.log('Nouvelle alerte !', alert);
+// });
+// ───────────────────────────────────────────────────────────
+export function onAlert(callback) {
+ alertCallbacks.push(callback);
+}
+
+// ───────────────────────────────────────────────────────────
+// FONCTION : Se déconnecter
+// ───────────────────────────────────────────────────────────
+// Appelle cette fonction quand l'utilisateur se déconnecte
+// de ton site (logout)
+// ───────────────────────────────────────────────────────────
+export function disconnectFromAlerts() {
+ if (socket !== null) {
+ socket.disconnect();
+ socket = null;
+ alertCallbacks = [];
+ console.log('👋 Déconnecté du serveur d\'alertes');
+ }
+}
+
+// ───────────────────────────────────────────────────────────
+// FONCTION : Vérifier si connecté
+// ───────────────────────────────────────────────────────────
+// Retourne true si connecté, false sinon
+// ───────────────────────────────────────────────────────────
+export function isConnected() {
+ return socket !== null && socket.connected;
+}
--- /dev/null
+body {
+ background: linear-gradient(135deg, #0f172a, #020617);
+ color: white;
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+}
+
+.main-content {
+ flex: 1;
+}
+
+.card {
+ background: rgba(255, 255, 255, 0.05);
+ border: none;
+ color: white;
+}
+
+/* Signal */
+
+.signal-box {
+ text-align: center;
+ padding: 20px;
+ border-radius: 10px;
+}
+
+.buy {
+ background: rgba(22,163,74,0.2);
+ color: #4ade80;
+}
+
+.sell {
+ background: rgba(220,38,38,0.2);
+ color: #f87171;
+}
+
+.hold {
+ background: rgba(234,179,8,0.2);
+ color: #fde047;
+}
+
+.value {
+ font-size: 28px;
+ font-weight: bold;
+}
+
+/* Inputs */
+
+.form-control,
+.form-select {
+ background-color: rgba(255,255,255,0.1);
+ color: white;
+ border: 1px solid rgba(255,255,255,0.2);
+}
+
+.form-control::placeholder {
+ color: #cbd5f5;
+}
+
+select.form-select {
+ background-color: rgba(255,255,255,0.1);
+ color: white;
+}
+
+select.form-select option {
+ background-color: #0f172a;
+ color: white;
+}
\ No newline at end of file