]> git.digitality.be Git - pdw25-26/commitdiff
fix(web): script.js corrections API - champs corrects + SERVER_URL dynamique
authorSteph Ponzo <ponzo.stephane2@gmail.com>
Sun, 1 Mar 2026 13:08:50 +0000 (14:08 +0100)
committerSteph Ponzo <ponzo.stephane2@gmail.com>
Sun, 1 Mar 2026 13:08:50 +0000 (14:08 +0100)
Wallette/web/script.js

index b8202869a7960ca6dfaa935d8ca659cfe461fa0d..3e80fa486c04b44bf1b5baad8728d48b781fd811 100644 (file)
 // script.js (module)
 import {
-  connectToAlerts,
-  onAlert,
-  disconnectFromAlerts,
-  isConnected
+    connectToAlerts,
+    onAlert,
+    disconnectFromAlerts,
+    isConnected
 } from './socketService.js';
 
-const SERVER_URL = 'http://localhost:3000';
+// URL dynamique — fonctionne en local ET en production
+const SERVER_URL = window.location.origin;
 
-// Exemple : récupérer un userId (ici exemple statique, adapte-toi)
-const userId = 'user-123';
+// userId courant
+let userId = localStorage.getItem('wallette_userId') || 'user-123';
+
+// Pré-remplir le champ userId
+const userInput = document.getElementById("userIdInput");
+if (userInput) userInput.value = userId;
 
 // Connecter automatiquement à l'ouverture
 connectToAlerts(userId);
 
-
-//function api 
-
-// Charger historique alertes
-async function loadAlertHistory() {
-  try {
-    const res = await fetch(`${SERVER_URL}/api/alerts/history?userId=${userId}`);
-    const data = await res.json();
-
-    data.forEach(alert => {
-      // on réutilise EXACTEMENT la même logique que socket
-      handleAlert(alert);
-    });
-
-  } catch (err) {
-    console.error("Erreur historique alertes :", err);
-  }
+// ─────────────────────────────────────────────────────────────
+// UTILITAIRE : appel API générique
+// ─────────────────────────────────────────────────────────────
+async function apiFetch(path) {
+    const res = await fetch(SERVER_URL + path);
+    const json = await res.json();
+    if (!json.ok) throw new Error(json.error?.message || 'Erreur API');
+    return json.data;
 }
 
-// Charger prix actuel
+// ─────────────────────────────────────────────────────────────
+// PRIX ACTUEL
+// ─────────────────────────────────────────────────────────────
 async function loadCurrentPrice(pair = "BTC/EUR") {
-  try {
-    const res = await fetch(`${SERVER_URL}/api/prices/current?pair=${pair}`);
-    const data = await res.json();
-
-    const priceEl = document.getElementById("price");
-    if (priceEl && data.price !== undefined) {
-      const currency = pair.includes("USD") ? "USD" : "EUR";
-      priceEl.textContent = Number(data.price).toLocaleString('fr-FR', {
-        style: 'currency',
-        currency: currency
-      });
+    try {
+        const data = await apiFetch(`/api/price/current?pair=${encodeURIComponent(pair)}`);
+        const priceEl = document.getElementById("price");
+        if (!priceEl) return;
+        const currency = pair.includes("USD") ? "USD" : "EUR";
+        priceEl.textContent = Number(data.current_price).toLocaleString('fr-FR', {
+        style: 'currency', currency
+        });
+    } catch (err) {
+        console.error("Erreur prix actuel :", err);
+        const priceEl = document.getElementById("price");
+        if (priceEl) priceEl.textContent = "Indisponible";
     }
-
-  } catch (err) {
-    console.error("Erreur prix actuel :", err);
-  }
 }
 
-// Charger wallet utilisateur
-async function loadWallet() {
-  try {
-    const res = await fetch(`${SERVER_URL}/api/wallet/${userId}`);
-    const data = await res.json();
+// ─────────────────────────────────────────────────────────────
+// WALLETS
+// ─────────────────────────────────────────────────────────────
+async function loadWallets() {
+    const walletList = document.getElementById("walletList");
+    if (!walletList) return;
+
+    try {
+        const result = await apiFetch(`/api/wallets?userId=${encodeURIComponent(userId)}`);
+       const wallets = result.wallets || result || [];
+
+        walletList.innerHTML = '';
+
+        if (!wallets || wallets.length === 0) {
+        walletList.innerHTML = `<li class="list-group-item bg-transparent text-white">Aucun wallet chargé</li>`;
+        return;
+        }
+
+        const first = wallets[0];
+        const balanceEl = document.getElementById("balance");
+        if (balanceEl) balanceEl.textContent = `${first.balance ?? '0'} ${first.asset_symbol || 'BTC'}`;
+
+        wallets.forEach(wallet => {
+        const li = document.createElement('li');
+        li.className = 'list-group-item bg-transparent text-white';
+        li.style.cursor = 'pointer';
+        li.textContent = `${wallet.asset_symbol || '?'} — ${wallet.balance ?? '—'}`;
+        li.onclick = () => loadWalletEvents(wallet.wallet_id);
+        walletList.appendChild(li);
+        });
+
+        if (first.wallet_id) loadWalletEvents(first.wallet_id);
+
+    } catch (err) {
+        console.error("Erreur wallet :", err);
+        walletList.innerHTML = `<li class="list-group-item bg-transparent text-danger">Erreur : ${err.message}</li>`;
+    }
+}
 
-    const balanceEl = document.getElementById("balance");
-    if (balanceEl && data.balance !== undefined) {
-      balanceEl.textContent = data.balance + " BTC";
+// ─────────────────────────────────────────────────────────────
+// HISTORIQUE TRANSACTIONS
+// ─────────────────────────────────────────────────────────────
+async function loadWalletEvents(walletId) {
+    const eventsList = document.getElementById("walletEvents");
+    if (!eventsList) return;
+
+    try {
+        const events = await apiFetch(`/api/wallets/${walletId}/events`);
+
+        eventsList.innerHTML = '';
+
+        if (!events || events.length === 0) {
+        eventsList.innerHTML = `<li class="list-group-item bg-transparent text-white">Aucune transaction</li>`;
+        return;
+        }
+
+        events.forEach(ev => {
+        const li = document.createElement('li');
+        li.className = 'list-group-item bg-transparent text-white d-flex justify-content-between';
+        const date = new Date(ev.timestamp_ms || ev.created_at_ms || Date.now()).toLocaleString('fr-FR');
+        const typeClass = ev.event_type === 'CREDIT' ? 'text-success' : 'text-danger';
+        li.innerHTML = `
+            <span><strong class="${typeClass}">${ev.event_type || '?'}</strong>
+            <small class="text-muted ms-2">${date}</small></span>
+            <span>${ev.amount ?? '—'} ${ev.asset_symbol || ''}</span>
+        `;
+        eventsList.appendChild(li);
+        });
+
+    } catch (err) {
+        console.error("Erreur historique transactions :", err);
     }
+}
 
-  } catch (err) {
-    console.error("Erreur wallet :", err);
-  }
+// ─────────────────────────────────────────────────────────────
+// SIGNAL ACTUEL
+// ─────────────────────────────────────────────────────────────
+async function loadCurrentSignal() {
+    try {
+        const signal = await apiFetch(`/api/signal/current?userId=${encodeURIComponent(userId)}&pair=BTC/EUR`);
+
+        const box      = document.getElementById('signalBox');
+        const actionEl = document.getElementById('signalAction');
+        const critEl   = document.getElementById('signalCriticality');
+        const confEl   = document.getElementById('signalConfidence');
+        const reasonEl = document.getElementById('signalReason');
+
+        if (!box) return;
+
+        const action = signal.action || 'HOLD';
+        box.className = 'signal-box ' + action.toLowerCase();
+        if (actionEl) actionEl.textContent = action;
+        if (critEl)   critEl.textContent   = signal.criticality || signal.alertLevel || 'INFO';
+        if (confEl)   confEl.textContent   = typeof signal.confidence === 'number'
+        ? Math.round(signal.confidence * 100) + '%' : '—';
+        if (reasonEl) reasonEl.textContent = signal.reason || '—';
+
+    } catch (err) {
+        const reasonEl = document.getElementById('signalReason');
+        if (reasonEl) reasonEl.textContent = 'Signal non disponible';
+    }
 }
 
-// Quand une alerte arrive, l'ajouter dans la liste #alertList
+// ─────────────────────────────────────────────────────────────
+// GESTION ALERTES SOCKET.IO
+// ─────────────────────────────────────────────────────────────
 function handleIncomingAlert(alert) {
+    console.log('Nouvelle alerte reçue :', alert);
 
-  console.log('Nouvelle alerte reçue dans main.js :', alert);
-
-  const list = document.getElementById('alertList');
-  if (!list) return;
-
-  const li = document.createElement('li');
+    const list = document.getElementById('alertList');
+    if (!list) return;
 
-  li.className = 'list-group-item bg-transparent text-white';
+    const placeholder = list.querySelector('li');
+    if (placeholder && placeholder.textContent.includes('Aucune')) placeholder.remove();
 
-  // 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);
-  }
-
-   // 1) Supprimer "Aucune alerte" si présent
-  const placeholder = document.getElementById('noAlerts');
-  if (placeholder) placeholder.remove();
-
-  // 2) Appliquer couleur selon BUY / SELL / HOLD
-  if (typeof alert === 'object' && alert.action) {
-    const action = alert.action.toUpperCase();
-    if (action === 'BUY') li.classList.add('buy');
-    else if (action === 'SELL') li.classList.add('sell');
-    else li.classList.add('hold');
-  }
-
-  // 3) Mettre à jour le bloc signal (si présent)
-  if (typeof alert === 'object') {
-    const box = document.getElementById('signalBox');
+    const box      = document.getElementById('signalBox');
     const actionEl = document.getElementById('signalAction');
-    const critEl = document.getElementById('signalCriticality');
-    const confEl = document.getElementById('signalConfidence');
+    const critEl   = document.getElementById('signalCriticality');
+    const confEl   = document.getElementById('signalConfidence');
     const reasonEl = document.getElementById('signalReason');
 
-    if (box && actionEl && critEl && confEl && reasonEl) {
-      const action = alert.action || 'HOLD';
-      box.className = 'signal-box ' + action.toLowerCase();
-      actionEl.textContent = action;
-      critEl.textContent = alert.alertLevel || 'INFO';
-      confEl.textContent =
-        typeof alert.confidence === 'number'
-          ? Math.round(alert.confidence * 100) + '%'
-          : '—';
-      reasonEl.textContent = alert.reason || alert.message || '—';
+    if (typeof alert === 'object') {
+        const action = (alert.action || 'HOLD').toUpperCase();
+        if (box)      box.className        = 'signal-box ' + action.toLowerCase();
+        if (actionEl) actionEl.textContent = action;
+        if (critEl)   critEl.textContent   = alert.alertLevel || 'INFO';
+        if (confEl)   confEl.textContent   = typeof alert.confidence === 'number'
+        ? Math.round(alert.confidence * 100) + '%' : '—';
+        if (reasonEl) reasonEl.textContent = alert.reason || alert.message || '—';
     }
-  }
-
-  // 4) Notification popup simple (si container existe)
-  const popupContainer = document.getElementById('popupContainer');
-  if (popupContainer) {
-    const pop = document.createElement('div');
-    pop.className = 'notification-popup';
-    pop.textContent = li.textContent;
-    popupContainer.appendChild(pop);
-
-    setTimeout(() => pop.remove(), 6000);
-  }
-
-  if (typeof alert === 'object') {
-
-    // Date & heure
-    const d = new Date(alert.timestamp || Date.now());
-    const dateStr = d.toLocaleString('fr-FR', {
-      day: '2-digit',
-      month: '2-digit',
-      year: 'numeric',
-      hour: '2-digit',
-      minute: '2-digit'
-    });
-
-    // Level
-    const level = alert.alertLevel || alert.level || 'INFO';
 
-    // Action
-    const action = alert.action || 'HOLD';
+    const li = document.createElement('li');
+    li.className = 'list-group-item bg-transparent text-white';
+
+    if (typeof alert === 'object') {
+        const d = new Date(alert.timestamp || Date.now());
+        const dateStr = d.toLocaleString('fr-FR', {
+        day:'2-digit', month:'2-digit', year:'numeric', hour:'2-digit', minute:'2-digit'
+        });
+
+        const level  = (alert.alertLevel || alert.level || 'INFO').toUpperCase();
+        const action = (alert.action || 'HOLD').toUpperCase();
+
+        let badgeClass = 'bg-info text-dark';
+        if (level === 'CRITICAL') badgeClass = 'bg-danger';
+        else if (level === 'WARNING') badgeClass = 'bg-warning text-dark';
+
+        let actionClass = 'text-warning';
+        if (action === 'BUY') actionClass = 'text-success';
+        if (action === 'SELL' || action === 'STOP_LOSS') actionClass = 'text-danger';
+
+        const currency = (alert.pair || '').includes('USD') ? 'USD' : 'EUR';
+        const priceStr = alert.price != null
+        ? Number(alert.price).toLocaleString('fr-FR', { style:'currency', currency }) : '';
+
+        const pair = alert.pair || '';
+        const conf = typeof alert.confidence === 'number'
+        ? ` • confiance ${Math.round(alert.confidence * 100)}%` : '';
+
+        li.innerHTML = `
+        <div style="display:flex; gap:8px; align-items:center; flex-wrap:wrap;">
+            <small class="text-muted">${dateStr}</small>
+            <span class="badge ${badgeClass}">${level}</span>
+            <strong class="${actionClass}">${action}</strong>
+            ${priceStr ? `<span style="font-weight:600;">${priceStr}</span>` : ''}
+        </div>
+        <div style="margin-top:4px; font-size:0.85rem; color:#cbd5e1;">
+            ${pair}${conf}
+        </div>
+        `;
+    } else {
+        li.textContent = String(alert);
+    }
 
-    // Prix (si présent)
-    let priceStr = '';
-    if (alert.price !== undefined) {
-      const currency = (alert.pair && alert.pair.includes('USD')) ? 'USD' : 'EUR';
-      priceStr = Number(alert.price).toLocaleString('fr-FR', {
-        style: 'currency',
-        currency: currency
-      });
+    const popupContainer = document.getElementById('popupContainer');
+    if (popupContainer) {
+        const pop = document.createElement('div');
+        pop.className = 'notification-popup';
+        pop.textContent = `${alert.action || ''} ${alert.pair || ''} — ${alert.reason || ''}`;
+        popupContainer.appendChild(pop);
+        setTimeout(() => pop.remove(), 6000);
     }
 
-    // Pair + confiance
-    const pair = alert.pair || '';
-    const conf = typeof alert.confidence === 'number'
-      ? ` • confiance ${Math.round(alert.confidence * 100)}%`
-      : '';
-
-    // Badge couleur level
-    let badgeClass = 'bg-primary';
-    const lvl = level.toUpperCase();
-
-    if (lvl.includes('DANGER') || lvl.includes('CRITICAL')) badgeClass = 'bg-danger';
-    else if (lvl.includes('WARNING')) badgeClass = 'bg-warning text-dark';
-    else if (lvl.includes('INFO')) badgeClass = 'bg-info text-dark';
-
-    // Appliquer affichage formaté (remplace le texte brut)
-    li.innerHTML = `
-      <div style="display:flex; gap:8px; align-items:center; flex-wrap:wrap;">
-        <small class="text-muted">${dateStr}</small>
-        <span class="badge ${badgeClass}">${lvl}</span>
-        <strong>${action}</strong>
-        ${priceStr ? `<span style="font-weight:600;">${priceStr}</span>` : ''}
-      </div>
-      <div style="margin-top:4px; font-size:0.85rem; color:#cbd5e1;">
-        ${pair}${conf}
-      </div>
-    `;
-  }
-
-
-   // Préfixer pour voir les nouvelles alertes en haut
-  list.prepend(li);
+    list.prepend(li);
 }
 
-// Socket temps réel
-onAlert(function(alert) {
-  handleIncomingAlert(alert);
-});
+onAlert(handleIncomingAlert);
+
+// ─────────────────────────────────────────────────────────────
+// BOUTONS
+// ─────────────────────────────────────────────────────────────
+document.getElementById("saveUserBtn")?.addEventListener("click", () => {
+    const input = document.getElementById("userIdInput");
+    if (input?.value.trim()) {
+        userId = input.value.trim();
+        localStorage.setItem('wallette_userId', userId);
+        alert("User ID sauvegardé : " + userId);
+        loadWallets();
+        loadCurrentSignal();
+    }
+    });
 
-loadAlertHistory();
-loadCurrentPrice();
-loadWallet();
+    document.getElementById("connectBtn")?.addEventListener("click", () => {
+    connectToAlerts(userId);
+    const st = document.getElementById("connStatus");
+    if (st) { st.className = "badge bg-success"; st.textContent = "Statut : on"; }
+    });
 
-// Déconnexion propre à la fermeture de la page
-window.addEventListener('beforeunload', () => {
-  if (isConnected()) {
+    document.getElementById("disconnectBtn")?.addEventListener("click", () => {
     disconnectFromAlerts();
-  }
+    const st = document.getElementById("connStatus");
+    if (st) { st.className = "badge bg-secondary"; st.textContent = "Statut : off"; }
+    });
+
+    // ─────────────────────────────────────────────────────────────
+    // CHARGEMENT INITIAL
+    // ─────────────────────────────────────────────────────────────
+    loadCurrentPrice();
+    loadWallets();
+    loadCurrentSignal();
+    setInterval(loadCurrentPrice, 30000);
+    setInterval(loadCurrentSignal, 15000);
+
+    window.addEventListener('beforeunload', () => {
+    if (isConnected()) disconnectFromAlerts();
 });
 
-// Exposer pour debug dans console
-window._alertsService = { connectToAlerts, disconnectFromAlerts, isConnected };
\ No newline at end of file
+window._alertsService = { connectToAlerts, disconnectFromAlerts, isConnected };