From 2b9b9771e1bb48d811b4f4b3fcefe97a257cad6e Mon Sep 17 00:00:00 2001 From: NicolasCantu Date: Wed, 29 Oct 2025 21:36:00 +0100 Subject: [PATCH] Remove forceWalletGeneration and create standardized page template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Motivations :** - forceWalletGeneration() recréait un wallet vierge au lieu d'utiliser le wallet préparé - Les pages avaient des styles incohérents et des problèmes d'affichage - Besoin d'un template standardisé pour toutes les pages d'initialisation **Modifications :** - service.ts : Suppression de forceWalletGeneration() dans restoreDevice() - src/templates/page-template.html : Template HTML standardisé pour toutes les pages - src/utils/page-template.utils.ts : Classe utilitaire pour gérer le template - src/pages/pairing/pairing.html : Refonte avec le template standardisé - src/pages/pairing/pairing.ts : Utilisation du template avec PageTemplate - src/pages/block-sync/block-sync.html : Refonte avec le template standardisé - src/pages/block-sync/block-sync.ts : Utilisation du template avec PageTemplate **Pages affectées :** - src/services/service.ts : Suppression de la génération forcée de wallet - src/templates/ : Nouveau template standardisé - src/utils/page-template.utils.ts : Nouvelle classe utilitaire - src/pages/pairing/ : Refonte complète avec template - src/pages/block-sync/ : Refonte complète avec template --- src/pages/block-sync/block-sync.html | 140 ++++++------ src/pages/block-sync/block-sync.ts | 305 +++++++++------------------ src/pages/pairing/pairing.html | 175 ++++++++++++++- src/pages/pairing/pairing.ts | 45 ++-- src/services/service.ts | 12 +- src/templates/page-template.html | 199 +++++++++++++++++ src/utils/page-template.utils.ts | 211 ++++++++++++++++++ 7 files changed, 777 insertions(+), 310 deletions(-) create mode 100644 src/templates/page-template.html create mode 100644 src/utils/page-template.utils.ts diff --git a/src/pages/block-sync/block-sync.html b/src/pages/block-sync/block-sync.html index 8e8bd89..0cd586a 100644 --- a/src/pages/block-sync/block-sync.html +++ b/src/pages/block-sync/block-sync.html @@ -3,7 +3,8 @@ - Synchronisation des Blocs - LeCoffre + Synchronisation des blocs - LeCoffre +
-

🔄 Synchronisation des Blocs

-

Synchronisation avec le réseau Bitcoin pour récupérer l'historique des transactions

+

🔄 Synchronisation des blocs

+

Synchronisation du wallet avec la blockchain

- 🔄 Initialisation de la synchronisation... + 🔄 Initialisation en cours...
-
-
-
- -
-

📊 Détails de la synchronisation

-
- Hauteur de bloc actuelle: - En attente... -
-
- Date anniversaire: - En attente... -
-
- Blocs à scanner: - En attente... -
-
- Blocs scannés: - 0 -
-
- Transactions trouvées: - 0 + -
- + \ No newline at end of file diff --git a/src/pages/block-sync/block-sync.ts b/src/pages/block-sync/block-sync.ts index ff51888..0efaefd 100644 --- a/src/pages/block-sync/block-sync.ts +++ b/src/pages/block-sync/block-sync.ts @@ -1,124 +1,40 @@ import { checkPBKDF2Key, checkWalletWithRetries } from '../../utils/prerequisites.utils'; +import { createPageTemplate } from '../../utils/page-template.utils'; document.addEventListener("DOMContentLoaded", async () => { console.log("🔄 Block sync page loaded"); - const status = document.getElementById("status") as HTMLElement; - const progressBar = document.getElementById("progressBar") as HTMLElement; - const continueBtn = document.getElementById("continueBtn") as HTMLButtonElement; - - function updateStatus(message: string, type: 'loading' | 'success' | 'error') { - if (status) { - status.textContent = message; - status.className = `status ${type}`; - } - } - - function updateProgress(percentage: number) { - if (progressBar) { - progressBar.style.width = `${percentage}%`; - } - } - - function updateSyncItem(elementId: string, value: string, status: 'pending' | 'completed' | 'error' = 'pending') { - const element = document.getElementById(elementId); - if (element) { - element.textContent = value; - element.className = `sync-status ${status}`; - } - } - - // Gestion du bouton continuer (définie avant le try pour être toujours disponible) - if (continueBtn) { - continueBtn.addEventListener('click', async () => { - console.log('🔗 Redirecting to pairing page...'); - // Rediriger vers la page de pairing standalone - window.location.href = '/src/pages/pairing/pairing.html'; - }); - } + // Initialiser le template de page + const pageTemplate = createPageTemplate(); try { - // Étape 1: Vérification des prérequis - updateStatus('🔍 Vérification des prérequis...', 'loading'); - updateProgress(10); + // Vérifier les prérequis + console.log('🔍 Verifying prerequisites...'); + pageTemplate.updateStatus('🔍 Vérification des prérequis...', 'loading'); - // Vérifier que le PBKDF2 key existe d'abord (prérequis le plus basique) const pbkdf2KeyResult = await checkPBKDF2Key(); if (!pbkdf2KeyResult) { - console.log('⚠️ PBKDF2 key not found in pbkdf2keys store, redirecting to security-setup...'); - updateStatus('⚠️ Redirection vers la configuration de sécurité...', 'loading'); + console.log('⚠️ PBKDF2 key not found, redirecting to security-setup...'); + pageTemplate.updateStatus('⚠️ Redirection vers la configuration de sécurité...', 'loading'); setTimeout(() => { window.location.href = '/src/pages/security-setup/security-setup.html'; }, 1000); return; } - // Vérifier que le wallet existe en base (avec plusieurs tentatives pour gérer les problèmes de synchronisation) const wallet = await checkWalletWithRetries(); if (!wallet) { - console.log('⚠️ Wallet still not found after retries, redirecting to wallet-setup...'); - updateStatus('⚠️ Redirection vers la configuration du wallet...', 'loading'); + console.log('⚠️ Wallet not found, redirecting to wallet-setup...'); + pageTemplate.updateStatus('⚠️ Redirection vers la configuration du wallet...', 'loading'); setTimeout(() => { window.location.href = '/src/pages/wallet-setup/wallet-setup.html'; }, 1000); return; } - // Vérifier que le wallet contient bien les données attendues - if (wallet.sp_wallet?.birthday !== undefined) { - console.log('✅ Wallet found in database with birthday:', wallet.sp_wallet.birthday); - } else { - throw new Error('Wallet found but missing required data (sp_wallet or birthday)'); - } - - // Étape 2: Initialisation des services - updateStatus('🔄 Initialisation des services...', 'loading'); - updateProgress(20); - - const { default: Services } = await import('../../services/service'); - if (!Services) { - throw new Error('Services class not found in default export'); - } - - console.log('🔄 Waiting for services to be ready...'); - let attempts = 0; - const maxAttempts = 30; - const delayMs = 2000; - - let services; - while (attempts < maxAttempts) { - try { - console.log(`🔄 Attempting to get services (attempt ${attempts + 1}/${maxAttempts})...`); - services = await Services.getInstance(); - console.log('✅ Services initialized successfully'); - break; - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - console.log(`⏳ Services not ready yet (attempt ${attempts + 1}/${maxAttempts}):`, errorMessage); - - // Si c'est une erreur de mémoire, arrêter immédiatement - if (errorMessage.includes('Out of memory') || errorMessage.includes('insufficient memory')) { - console.error('🚫 Memory error detected - stopping retry attempts'); - updateStatus('❌ Erreur: Mémoire insuffisante. Veuillez actualiser la page.', 'error'); - throw new Error('WebAssembly initialization failed due to insufficient memory. Please refresh the page.'); - } - - attempts++; - if (attempts >= maxAttempts) { - throw new Error(`Services failed to initialize after ${maxAttempts} attempts.`); - } - await new Promise(resolve => setTimeout(resolve, delayMs)); - } - } - - if (!services) { - throw new Error('Services not initialized'); - } - - // Vérifier que le birthday est configuré (> 0) - if (!wallet.sp_wallet.birthday || wallet.sp_wallet.birthday === 0) { - console.log('⚠️ Birthday not configured (birthday = 0), redirecting to birthday-setup...'); - updateStatus('⚠️ Redirection vers la configuration de la date anniversaire...', 'loading'); + if (!wallet.sp_wallet?.birthday || wallet.sp_wallet.birthday === 0) { + console.log('⚠️ Birthday not configured, redirecting to birthday-setup...'); + pageTemplate.updateStatus('⚠️ Redirection vers la configuration de la date anniversaire...', 'loading'); setTimeout(() => { window.location.href = '/src/pages/birthday-setup/birthday-setup.html'; }, 1000); @@ -126,64 +42,78 @@ document.addEventListener("DOMContentLoaded", async () => { } console.log('✅ All prerequisites verified for block sync'); + pageTemplate.updateStatus('✅ Prerequisites verified', 'success'); - // Étape 3: Connexion aux relais si nécessaire - updateStatus('🔗 Connexion aux relais...', 'loading'); - updateProgress(40); + // Afficher les étapes de synchronisation + pageTemplate.showSteps(); + pageTemplate.updateStep('currentBlock', 'En attente...', 'pending'); + pageTemplate.updateStep('birthday', wallet.sp_wallet.birthday.toString(), 'completed'); + pageTemplate.updateStep('lastScan', 'En attente...', 'pending'); + pageTemplate.updateStep('syncStatus', 'En attente...', 'pending'); - let currentBlockHeight = services.getCurrentBlockHeight(); - if (currentBlockHeight === -1 || currentBlockHeight === 0) { - console.log('⚠️ Block height not available, connecting to relays...'); - await services.connectAllRelays(); + // Initialiser les services + console.log('🔄 Waiting for services to be ready...'); + pageTemplate.updateStatus('🔄 Initialisation des services...', 'loading'); - // Attendre que le handshake arrive et que chain_tip soit défini - await new Promise((resolve, reject) => { - const timeout = setTimeout(() => { - reject(new Error('Timeout waiting for block height from handshake')); - }, 15000); // 15 secondes de timeout + let services: Services; + let attempts = 0; + const maxAttempts = 30; - const checkBlockHeight = () => { - const blockHeight = services.getCurrentBlockHeight(); - if (blockHeight !== -1 && blockHeight > 0) { - console.log(`✅ Block height set from handshake: ${blockHeight}`); - currentBlockHeight = blockHeight; - clearTimeout(timeout); - resolve(); - } else { - setTimeout(checkBlockHeight, 100); - } - }; - - checkBlockHeight(); - }); + while (attempts < maxAttempts) { + try { + console.log(`🔄 Attempting to get services (attempt ${attempts + 1}/${maxAttempts})...`); + services = await Services.getInstance(); + console.log('✅ Services initialized successfully'); + break; + } catch (error) { + attempts++; + console.log(`⚠️ Services initialization failed (attempt ${attempts}/${maxAttempts}):`, error); + if (attempts >= maxAttempts) { + throw new Error('Failed to initialize services after maximum attempts'); + } + await new Promise(resolve => setTimeout(resolve, 1000)); + } } - // Étape 4: Récupération des informations de synchronisation - updateStatus('📊 Récupération des informations de synchronisation...', 'loading'); - updateProgress(50); + if (!services!) { + throw new Error('Services not initialized'); + } + // Vérifier si le wallet est déjà synchronisé + const currentBlockHeight = services.getCurrentBlockHeight(); + if (currentBlockHeight === -1) { + console.log('⚠️ Block height not available, connecting to relays...'); + pageTemplate.updateStatus('⚠️ Connexion aux relays...', 'loading'); + + // Attendre que les services se connectent aux relays + await services.connectAllRelays(); + + // Attendre que la hauteur de bloc soit définie + await services.waitForBlockHeight(); + } + + const finalBlockHeight = services.getCurrentBlockHeight(); const birthday = wallet.sp_wallet.birthday; - const lastScan = wallet.sp_wallet.last_scan || birthday; - const blocksToScan = currentBlockHeight - lastScan; + const lastScan = wallet.sp_wallet.last_scan || 0; + const toScan = Math.max(0, finalBlockHeight - lastScan); - // Mettre à jour l'interface avec les informations - updateSyncItem('currentBlock', currentBlockHeight.toString(), 'completed'); - updateSyncItem('birthday', birthday.toString(), 'completed'); - updateSyncItem('blocksToScan', blocksToScan.toString(), 'pending'); + console.log(`📊 Sync info: current=${finalBlockHeight}, birthday=${birthday}, lastScan=${lastScan}, toScan=${toScan}`); - console.log(`📊 Sync info: current=${currentBlockHeight}, birthday=${birthday}, lastScan=${lastScan}, toScan=${blocksToScan}`); + // Mettre à jour les étapes + pageTemplate.updateStep('currentBlock', finalBlockHeight.toString(), 'completed'); + pageTemplate.updateStep('lastScan', lastScan.toString(), 'completed'); - // Vérifier si une synchronisation est nécessaire - if (blocksToScan <= 0) { + if (toScan === 0) { console.log('✅ Wallet already synchronized'); - updateStatus('✅ Wallet déjà synchronisé!', 'success'); - updateProgress(100); - updateSyncItem('blocksScanned', lastScan.toString(), 'completed'); - updateSyncItem('blocksToScan', '0', 'completed'); - - // Redirection automatique après 3 secondes - updateStatus('✅ Redirection automatique vers le pairing dans 3 secondes...', 'success'); - continueBtn.disabled = false; + pageTemplate.updateStatus('✅ Wallet déjà synchronisé', 'success'); + pageTemplate.updateStep('syncStatus', 'Synchronisé', 'completed'); + + // Afficher le bouton et rediriger automatiquement + pageTemplate.showContinueButton('Aller au pairing', () => { + window.location.href = '/src/pages/pairing/pairing.html'; + }); + + // Auto-redirection après 3 secondes setTimeout(() => { console.log('🔗 Auto-redirecting to pairing page...'); window.location.href = '/src/pages/pairing/pairing.html'; @@ -191,11 +121,10 @@ document.addEventListener("DOMContentLoaded", async () => { return; } - // Étape 5: Synchronisation réelle des blocs - updateStatus('🔍 Synchronisation des blocs en cours...', 'loading'); - updateProgress(60); - - console.log(`🔄 Starting real block scan from ${lastScan} to ${currentBlockHeight}...`); + // Afficher la barre de progression + pageTemplate.showProgress(); + pageTemplate.updateStatus('🔄 Synchronisation en cours...', 'loading'); + pageTemplate.updateStep('syncStatus', 'En cours...', 'pending'); // Intercepter les messages de progression du scan let scanProgressInterval: NodeJS.Timeout | null = null; @@ -214,12 +143,12 @@ document.addEventListener("DOMContentLoaded", async () => { const percentage = parseInt(progressMatch[3]); // Mettre à jour l'interface avec les détails de progression - updateStatus(`🔍 Synchronisation des blocs: ${currentBlock}/${totalBlocks} (${percentage}%)`, 'loading'); - updateProgress(60 + (percentage * 0.4)); // 60% à 100% pour la synchronisation + pageTemplate.updateStatus(`🔍 Synchronisation des blocs: ${currentBlock}/${totalBlocks} (${percentage}%)`, 'loading'); + pageTemplate.updateProgress(60 + (percentage * 0.4)); // 60% à 100% pour la synchronisation // Mettre à jour les éléments de synchronisation - updateSyncItem('blocksScanned', currentBlock.toString(), 'pending'); - updateSyncItem('blocksToScan', (totalBlocks - currentBlock).toString(), 'pending'); + pageTemplate.updateStep('blocksScanned', currentBlock.toString(), 'pending'); + pageTemplate.updateStep('blocksToScan', (totalBlocks - currentBlock).toString(), 'pending'); lastProgressMessage = `Bloc ${currentBlock}/${totalBlocks} (${percentage}%)`; } @@ -228,80 +157,56 @@ document.addEventListener("DOMContentLoaded", async () => { originalConsoleLog.apply(console, args); }; - // Utiliser updateDeviceBlockHeight qui gère la synchronisation si nécessaire - // Cette méthode vérifie si last_scan < currentBlockHeight et synchronise si nécessaire try { + // Effectuer la synchronisation await services.updateDeviceBlockHeight(); console.log('✅ Block scan completed successfully'); // Restaurer la fonction console.log originale console.log = originalConsoleLog; - - // Vérifier que la mise à jour a été sauvegardée - const finalWallet = await services.getDeviceFromDatabase(); - if (finalWallet?.sp_wallet?.last_scan) { - const finalLastScan = finalWallet.sp_wallet.last_scan; - console.log('✅ Wallet updated with last_scan:', finalLastScan); - - // Finalisation - updateStatus('✅ Synchronisation terminée avec succès!', 'success'); - updateProgress(100); - updateSyncItem('blocksScanned', finalLastScan.toString(), 'completed'); - updateSyncItem('blocksToScan', blocksToScan.toString(), 'completed'); - - // Activer le bouton continuer - if (continueBtn) { - continueBtn.disabled = false; - } - - console.log('🎉 Block sync completed successfully'); - - // Redirection automatique après 3 secondes - updateStatus('✅ Redirection automatique vers le pairing dans 3 secondes...', 'success'); - setTimeout(() => { - console.log('🔗 Auto-redirecting to pairing page...'); - window.location.href = '/src/pages/pairing/pairing.html'; - }, 3000); - } else { - throw new Error('Failed to verify wallet update - last_scan not found'); - } + + pageTemplate.updateStatus('✅ Synchronisation terminée', 'success'); + pageTemplate.updateProgress(100); + pageTemplate.updateStep('syncStatus', 'Terminé', 'completed'); + + // Afficher le bouton et rediriger automatiquement + pageTemplate.showContinueButton('Aller au pairing', () => { + window.location.href = '/src/pages/pairing/pairing.html'; + }); + + // Auto-redirection après 3 secondes + setTimeout(() => { + console.log('🔗 Auto-redirecting to pairing page...'); + window.location.href = '/src/pages/pairing/pairing.html'; + }, 3000); + } catch (error) { // Restaurer la fonction console.log originale en cas d'erreur console.log = originalConsoleLog; console.error('❌ Error during block scan:', error); + pageTemplate.updateStatus(`❌ Erreur lors de la synchronisation: ${(error as Error).message}`, 'error'); + pageTemplate.updateStep('syncStatus', 'Erreur', 'error'); throw error; } } catch (error) { - console.error('❌ Error during block sync:', error); + console.error('❌ Error in block sync page:', error); + pageTemplate.updateStatus(`❌ Erreur: ${(error as Error).message}`, 'error'); + + // Rediriger vers la page appropriée selon l'erreur const errorMessage = (error as Error).message; - - updateStatus(`❌ Erreur: ${errorMessage}`, 'error'); - - // Si l'erreur est liée aux prérequis, rediriger vers la page appropriée if (errorMessage.includes('PBKDF2') || errorMessage.includes('security')) { - console.log('⚠️ Security error detected, redirecting to security-setup...'); - updateStatus('⚠️ Redirection vers la configuration de sécurité...', 'loading'); setTimeout(() => { window.location.href = '/src/pages/security-setup/security-setup.html'; }, 2000); } else if (errorMessage.includes('wallet') || errorMessage.includes('device')) { - console.log('⚠️ Wallet error detected, redirecting to wallet-setup...'); - updateStatus('⚠️ Redirection vers la configuration du wallet...', 'loading'); setTimeout(() => { window.location.href = '/src/pages/wallet-setup/wallet-setup.html'; }, 2000); } else if (errorMessage.includes('birthday')) { - console.log('⚠️ Birthday error detected, redirecting to birthday-setup...'); - updateStatus('⚠️ Redirection vers la configuration de la date anniversaire...', 'loading'); setTimeout(() => { window.location.href = '/src/pages/birthday-setup/birthday-setup.html'; }, 2000); - } else { - // Erreur générale, afficher et permettre de réessayer - updateSyncItem('currentBlock', 'Erreur', 'error'); - updateSyncItem('birthday', 'Erreur', 'error'); - updateSyncItem('blocksToScan', 'Erreur', 'error'); } } -}); +}); \ No newline at end of file diff --git a/src/pages/pairing/pairing.html b/src/pages/pairing/pairing.html index 7a750d4..6cc8a19 100644 --- a/src/pages/pairing/pairing.html +++ b/src/pages/pairing/pairing.html @@ -30,12 +30,14 @@ text-align: center; color: #333; margin-bottom: 10px; + font-size: 2.5rem; } .subtitle { text-align: center; color: #666; margin-bottom: 30px; + font-size: 1.1rem; } .status { @@ -43,6 +45,11 @@ padding: 20px; border-radius: 8px; margin-bottom: 20px; + font-size: 1rem; + min-height: 60px; + display: flex; + align-items: center; + justify-content: center; } .status.loading { @@ -60,9 +67,156 @@ color: #c62828; } - #pairing-content { + .progress-container { + margin: 20px 0; + } + + .progress-bar { + width: 100%; + height: 8px; + background: #e0e0e0; + border-radius: 4px; + overflow: hidden; + } + + .progress-fill { + height: 100%; + background: linear-gradient(90deg, #4caf50, #8bc34a); + width: 0%; + transition: width 0.3s ease; + } + + .steps-container { + margin: 20px 0; + } + + .step-item { + display: flex; + align-items: center; + padding: 10px 0; + border-bottom: 1px solid #eee; + } + + .step-item:last-child { + border-bottom: none; + } + + .step-label { + flex: 1; + font-weight: 500; + color: #333; + } + + .step-value { + font-weight: 600; + color: #666; + } + + .step-status { + margin-left: 10px; + padding: 4px 8px; + border-radius: 4px; + font-size: 0.8rem; + font-weight: 500; + } + + .step-status.pending { + background: #fff3cd; + color: #856404; + } + + .step-status.completed { + background: #d4edda; + color: #155724; + } + + .step-status.error { + background: #f8d7da; + color: #721c24; + } + + .continue-btn { + width: 100%; + padding: 15px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + border: none; + border-radius: 8px; + font-size: 1.1rem; + font-weight: 600; + cursor: pointer; + transition: transform 0.2s ease, box-shadow 0.2s ease; + margin-top: 20px; + } + + .continue-btn:hover:not(:disabled) { + transform: translateY(-2px); + box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3); + } + + .continue-btn:disabled { + background: #ccc; + cursor: not-allowed; + transform: none; + box-shadow: none; + } + + .content-area { min-height: 200px; } + + /* Styles spécifiques au pairing */ + .pairing-container { + background: #f8f9fa; + border-radius: 8px; + padding: 20px; + margin: 20px 0; + } + + .pairing-card { + background: white; + border-radius: 8px; + padding: 20px; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); + } + + .card-header h2 { + margin: 0 0 10px 0; + color: #333; + font-size: 1.5rem; + } + + .card-description { + color: #666; + margin: 0 0 20px 0; + } + + .status-indicator { + background: #e3f2fd; + color: #1976d2; + padding: 15px; + border-radius: 8px; + text-align: center; + margin: 20px 0; + } + + .account-actions { + margin-top: 20px; + } + + .danger-btn { + background: #dc3545; + color: white; + border: none; + padding: 10px 20px; + border-radius: 6px; + cursor: pointer; + font-size: 0.9rem; + } + + .danger-btn:hover { + background: #c82333; + } @@ -74,12 +228,25 @@ 🔄 Initialisation en cours...
-
+ + + + +
+ +
- - + \ No newline at end of file diff --git a/src/pages/pairing/pairing.ts b/src/pages/pairing/pairing.ts index d196383..668a9e6 100644 --- a/src/pages/pairing/pairing.ts +++ b/src/pages/pairing/pairing.ts @@ -6,6 +6,7 @@ import { displayEmojis, generateCreateBtn, addressToEmoji, prepareAndSendPairing import { getCorrectDOM } from '../../utils/html.utils'; import { IframePairingComponent } from '../../components/iframe-pairing/iframe-pairing'; import { checkPBKDF2Key, checkWalletWithRetries } from '../../utils/prerequisites.utils'; +import { createPageTemplate } from '../../utils/page-template.utils'; import loginHtml from '../home/home.html?raw'; // Extend WindowEventMap to include custom events @@ -19,6 +20,7 @@ declare global { } let isInitializing = false; +let pageTemplate: any; document.addEventListener('DOMContentLoaded', async () => { if (isInitializing) { @@ -29,19 +31,12 @@ document.addEventListener('DOMContentLoaded', async () => { isInitializing = true; console.log('🔐 Pairing page loaded'); - const status = document.getElementById('status') as HTMLElement; - const pairingContent = document.getElementById('pairing-content') as HTMLElement; - - function updateStatus(message: string, type: 'loading' | 'success' | 'error') { - if (status) { - status.textContent = message; - status.className = `status ${type}`; - } - } + // Initialiser le template de page + pageTemplate = createPageTemplate(); // Vérifier les prérequis en base de données console.log('🔍 Verifying prerequisites...'); - updateStatus('🔍 Vérification des prérequis...', 'loading'); + pageTemplate.updateStatus('🔍 Vérification des prérequis...', 'loading'); try { console.log('🔧 Getting device reader service...'); @@ -51,7 +46,7 @@ document.addEventListener('DOMContentLoaded', async () => { const pbkdf2KeyResult = await checkPBKDF2Key(); if (!pbkdf2KeyResult) { console.log('⚠️ PBKDF2 key not found, redirecting to security-setup...'); - updateStatus('⚠️ Redirection vers la configuration de sécurité...', 'loading'); + pageTemplate.updateStatus('⚠️ Redirection vers la configuration de sécurité...', 'loading'); setTimeout(() => { window.location.href = '/src/pages/security-setup/security-setup.html'; }, 1000); @@ -62,7 +57,7 @@ document.addEventListener('DOMContentLoaded', async () => { const wallet = await checkWalletWithRetries(); if (!wallet) { console.log('⚠️ Wallet still not found after retries, redirecting to wallet-setup...'); - updateStatus('⚠️ Redirection vers la configuration du wallet...', 'loading'); + pageTemplate.updateStatus('⚠️ Redirection vers la configuration du wallet...', 'loading'); setTimeout(() => { window.location.href = '/src/pages/wallet-setup/wallet-setup.html'; }, 1000); @@ -79,7 +74,7 @@ document.addEventListener('DOMContentLoaded', async () => { // Vérifier que le birthday est configuré (> 0) if (!wallet.sp_wallet.birthday || wallet.sp_wallet.birthday === 0) { console.log('⚠️ Birthday not configured, redirecting to birthday-setup...'); - updateStatus('⚠️ Redirection vers la configuration de la date anniversaire...', 'loading'); + pageTemplate.updateStatus('⚠️ Redirection vers la configuration de la date anniversaire...', 'loading'); setTimeout(() => { window.location.href = '/src/pages/birthday-setup/birthday-setup.html'; }, 1000); @@ -89,36 +84,24 @@ document.addEventListener('DOMContentLoaded', async () => { console.log('✅ All prerequisites verified for pairing page'); // Charger le contenu de pairing depuis home.html - updateStatus('🔄 Initialisation du pairing...', 'loading'); + pageTemplate.updateStatus('🔄 Initialisation du pairing...', 'loading'); - if (pairingContent) { - // Créer un conteneur simulant login-4nk-component pour getCorrectDOM - const mockContainer = document.createElement('div'); - mockContainer.id = 'login-4nk-component'; - mockContainer.className = 'login-4nk-component'; - - // Injecter le HTML dans le mockContainer - mockContainer.innerHTML = loginHtml; - - // Ajouter le mockContainer au contenu de pairing - pairingContent.appendChild(mockContainer); - } + // Injecter le contenu de pairing dans la zone de contenu + pageTemplate.setContent(loginHtml); // Importer et initialiser la logique de pairing depuis home.ts const { initHomePage } = await import('../home/home'); await initHomePage(); - updateStatus('✅ Prêt pour le pairing', 'success'); + pageTemplate.updateStatus('✅ Prêt pour le pairing', 'success'); setTimeout(() => { - if (status) { - status.style.display = 'none'; - } + pageTemplate.hideStatus(); }, 2000); console.log('✅ Pairing page initialization completed'); } catch (error) { console.error('❌ Error initializing pairing page:', error); - updateStatus(`❌ Erreur: ${(error as Error).message}`, 'error'); + pageTemplate.updateStatus(`❌ Erreur: ${(error as Error).message}`, 'error'); // Si l'erreur est liée aux prérequis, rediriger vers la page appropriée const errorMessage = (error as Error).message; diff --git a/src/services/service.ts b/src/services/service.ts index da33e70..187bfc8 100755 --- a/src/services/service.ts +++ b/src/services/service.ts @@ -2195,17 +2195,9 @@ export default class Services { public restoreDevice(device: Device) { try { this.sdkClient.restore_device(device); - - // Force wallet generation to ensure keys are available - console.log('🔧 Forcing wallet generation after restore...'); - try { - const wallet = this.sdkClient.dump_wallet(); - console.log('✅ Wallet restored:', wallet); - } catch (walletError) { - console.warn('⚠️ Wallet restoration failed:', walletError); - } + console.log('✅ Device restored successfully'); } catch (e) { - console.error(e); + console.error('❌ Error restoring device:', e); } } diff --git a/src/templates/page-template.html b/src/templates/page-template.html new file mode 100644 index 0000000..d85d8eb --- /dev/null +++ b/src/templates/page-template.html @@ -0,0 +1,199 @@ + + + + + + {{PAGE_TITLE}} - LeCoffre + + + + +
+

{{PAGE_ICON}} {{PAGE_TITLE}}

+

{{PAGE_SUBTITLE}}

+ +
+ {{INITIAL_STATUS}} +
+ + + + + +
+ +
+ + +
+ + + + diff --git a/src/utils/page-template.utils.ts b/src/utils/page-template.utils.ts new file mode 100644 index 0000000..545e9f9 --- /dev/null +++ b/src/utils/page-template.utils.ts @@ -0,0 +1,211 @@ +/** + * Utilitaire pour gérer le template standardisé des pages + */ +export class PageTemplate { + private container: HTMLElement; + private status: HTMLElement; + private progressContainer: HTMLElement; + private progressFill: HTMLElement; + private stepsContainer: HTMLElement; + private contentArea: HTMLElement; + private continueBtn: HTMLButtonElement; + + constructor() { + this.container = document.querySelector('.container') as HTMLElement; + this.status = document.getElementById('status') as HTMLElement; + this.progressContainer = document.getElementById('progressContainer') as HTMLElement; + this.progressFill = document.getElementById('progressFill') as HTMLElement; + this.stepsContainer = document.getElementById('stepsContainer') as HTMLElement; + this.contentArea = document.getElementById('contentArea') as HTMLElement; + this.continueBtn = document.getElementById('continueBtn') as HTMLButtonElement; + } + + /** + * Met à jour le statut de la page + */ + updateStatus(message: string, type: 'loading' | 'success' | 'error' = 'loading'): void { + if (this.status) { + this.status.textContent = message; + this.status.className = `status ${type}`; + } + } + + /** + * Cache le statut de la page + */ + hideStatus(): void { + if (this.status) { + this.status.style.display = 'none'; + } + } + + /** + * Affiche la barre de progression + */ + showProgress(): void { + if (this.progressContainer) { + this.progressContainer.style.display = 'block'; + } + } + + /** + * Cache la barre de progression + */ + hideProgress(): void { + if (this.progressContainer) { + this.progressContainer.style.display = 'none'; + } + } + + /** + * Met à jour le pourcentage de progression + */ + updateProgress(percentage: number): void { + if (this.progressFill) { + this.progressFill.style.width = `${Math.min(100, Math.max(0, percentage))}%`; + } + } + + /** + * Affiche les étapes + */ + showSteps(): void { + if (this.stepsContainer) { + this.stepsContainer.style.display = 'block'; + } + } + + /** + * Cache les étapes + */ + hideSteps(): void { + if (this.stepsContainer) { + this.stepsContainer.style.display = 'none'; + } + } + + /** + * Met à jour une étape + */ + updateStep(stepId: string, value: string, status: 'pending' | 'completed' | 'error' = 'pending'): void { + let stepElement = document.getElementById(stepId); + if (!stepElement) { + stepElement = document.createElement('div'); + stepElement.id = stepId; + stepElement.className = 'step-item'; + this.stepsContainer.appendChild(stepElement); + } + + stepElement.innerHTML = ` + ${this.getStepLabel(stepId)} + ${value} + ${this.getStatusText(status)} + `; + } + + /** + * Affiche le bouton continuer + */ + showContinueButton(text: string = 'Continuer', onClick?: () => void): void { + if (this.continueBtn) { + this.continueBtn.textContent = text; + this.continueBtn.style.display = 'block'; + this.continueBtn.disabled = false; + + if (onClick) { + this.continueBtn.onclick = onClick; + } + } + } + + /** + * Cache le bouton continuer + */ + hideContinueButton(): void { + if (this.continueBtn) { + this.continueBtn.style.display = 'none'; + } + } + + /** + * Désactive le bouton continuer + */ + disableContinueButton(): void { + if (this.continueBtn) { + this.continueBtn.disabled = true; + } + } + + /** + * Active le bouton continuer + */ + enableContinueButton(): void { + if (this.continueBtn) { + this.continueBtn.disabled = false; + } + } + + /** + * Injecte du contenu dans la zone de contenu + */ + setContent(html: string): void { + if (this.contentArea) { + this.contentArea.innerHTML = html; + } + } + + /** + * Ajoute du contenu à la zone de contenu + */ + addContent(html: string): void { + if (this.contentArea) { + this.contentArea.innerHTML += html; + } + } + + /** + * Vide la zone de contenu + */ + clearContent(): void { + if (this.contentArea) { + this.contentArea.innerHTML = ''; + } + } + + /** + * Obtient le label d'une étape + */ + private getStepLabel(stepId: string): string { + const labels: Record = { + 'currentBlock': 'Bloc actuel', + 'birthday': 'Date anniversaire', + 'blocksToScan': 'Blocs à scanner', + 'blocksScanned': 'Blocs scannés', + 'lastScan': 'Dernier scan', + 'syncStatus': 'Statut de synchronisation', + 'walletStatus': 'Statut du wallet', + 'credentialsStatus': 'Statut des credentials', + 'pairingStatus': 'Statut du pairing' + }; + return labels[stepId] || stepId; + } + + /** + * Obtient le texte du statut + */ + private getStatusText(status: 'pending' | 'completed' | 'error'): string { + const texts: Record = { + 'pending': 'En cours', + 'completed': 'Terminé', + 'error': 'Erreur' + }; + return texts[status] || status; + } +} + +/** + * Fonction utilitaire pour créer une instance de PageTemplate + */ +export function createPageTemplate(): PageTemplate { + return new PageTemplate(); +}