feat: create standalone pairing page like other setup pages

**Motivations :**
- Créer une page standalone pour le pairing comme les autres étapes (security-setup, wallet-setup, etc.)
- Uniformiser le format des pages de setup avec une structure HTML complète
- Faciliter la redirection depuis block-sync vers pairing

**Modifications :**
- Créer src/pages/pairing/pairing.html (page HTML complète comme les autres)
- Créer src/pages/pairing/pairing.ts (charge la logique depuis home.ts)
- Ajouter la route pairing dans router.ts
- Mettre à jour les redirections dans block-sync.ts pour utiliser pairing.html
- Mettre à jour checkStorageStateAndNavigate pour rediriger vers pairing

**Pages affectées :**
- src/pages/pairing/pairing.html (nouveau fichier)
- src/pages/pairing/pairing.ts (nouveau fichier)
- src/router.ts (ajout route pairing)
- src/pages/block-sync/block-sync.ts (redirection vers pairing.html)
This commit is contained in:
NicolasCantu 2025-10-29 17:27:27 +01:00
parent 5a1826034e
commit 47e3166851
4 changed files with 235 additions and 8 deletions

View File

@ -32,8 +32,8 @@ document.addEventListener("DOMContentLoaded", async () => {
if (continueBtn) {
continueBtn.addEventListener('click', async () => {
console.log('🔗 Redirecting to pairing page...');
// Rediriger vers la racine pour que le router charge la page home correctement
window.location.href = '/';
// Rediriger vers la page de pairing standalone
window.location.href = '/src/pages/pairing/pairing.html';
});
}
@ -186,7 +186,7 @@ document.addEventListener("DOMContentLoaded", async () => {
continueBtn.disabled = false;
setTimeout(() => {
console.log('🔗 Auto-redirecting to pairing page...');
window.location.href = '/';
window.location.href = '/src/pages/pairing/pairing.html';
}, 3000);
return;
}
@ -226,7 +226,7 @@ document.addEventListener("DOMContentLoaded", async () => {
updateStatus('✅ Redirection automatique vers le pairing dans 3 secondes...', 'success');
setTimeout(() => {
console.log('🔗 Auto-redirecting to pairing page...');
window.location.href = '/';
window.location.href = '/src/pages/pairing/pairing.html';
}, 3000);
} else {
throw new Error('Failed to verify wallet update - last_scan not found');

View File

@ -0,0 +1,85 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pairing - LeCoffre</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.container {
background: white;
border-radius: 12px;
padding: 40px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
max-width: 600px;
width: 100%;
}
h1 {
text-align: center;
color: #333;
margin-bottom: 10px;
}
.subtitle {
text-align: center;
color: #666;
margin-bottom: 30px;
}
.status {
text-align: center;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}
.status.loading {
background: #e3f2fd;
color: #1976d2;
}
.status.success {
background: #e8f5e8;
color: #2e7d32;
}
.status.error {
background: #ffebee;
color: #c62828;
}
#pairing-content {
min-height: 200px;
}
</style>
<link rel="stylesheet" href="../../4nk.css">
</head>
<body>
<div class="container">
<h1>🔐 Pairing</h1>
<p class="subtitle">Appairage sécurisé des appareils</p>
<div class="status loading" id="status">
🔄 Initialisation en cours...
</div>
<div id="pairing-content">
<!-- Le contenu de pairing sera injecté ici -->
</div>
</div>
<script type="module" src="./pairing.ts"></script>
</body>
</html>

View File

@ -0,0 +1,142 @@
import { DeviceReaderService } from '../../services/device-reader.service';
import { SecureCredentialsService } from '../../services/secure-credentials.service';
import { SecurityModeService } from '../../services/security-mode.service';
import { addSubscription } from '../../utils/subscription.utils';
import { displayEmojis, generateCreateBtn, addressToEmoji, prepareAndSendPairingTx } from '../../utils/sp-address.utils';
import { getCorrectDOM } from '../../utils/html.utils';
import { IframePairingComponent } from '../../components/iframe-pairing/iframe-pairing';
import { checkPBKDF2Key, checkWalletWithRetries } from '../../utils/prerequisites.utils';
import loginHtml from '../home/home.html?raw';
import loginCss from '../../4nk.css?raw';
// Extend WindowEventMap to include custom events
declare global {
interface WindowEventMap {
'pairing-words-generated': CustomEvent;
'pairing-status-update': CustomEvent;
'pairing-success': CustomEvent;
'pairing-error': CustomEvent;
}
}
let isInitializing = false;
document.addEventListener('DOMContentLoaded', async () => {
if (isInitializing) {
console.log('⚠️ Pairing page already initializing, skipping...');
return;
}
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}`;
}
}
// Vérifier les prérequis en base de données
console.log('🔍 Verifying prerequisites...');
updateStatus('🔍 Vérification des prérequis...', 'loading');
try {
console.log('🔧 Getting device reader service...');
const deviceReader = DeviceReaderService.getInstance();
// Vérifier que le PBKDF2 key existe d'abord
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');
setTimeout(() => {
window.location.href = '/src/pages/security-setup/security-setup.html';
}, 1000);
return;
}
// Vérifier que le wallet existe en base
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');
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)');
}
// 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');
setTimeout(() => {
window.location.href = '/src/pages/birthday-setup/birthday-setup.html';
}, 1000);
return;
}
console.log('✅ All prerequisites verified for pairing page');
// Charger le contenu de pairing depuis home.html
updateStatus('🔄 Initialisation du pairing...', 'loading');
if (pairingContent) {
pairingContent.innerHTML = `
<style>
${loginCss}
</style>
${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');
setTimeout(() => {
if (status) {
status.style.display = 'none';
}
}, 2000);
console.log('✅ Pairing page initialization completed');
} catch (error) {
console.error('❌ Error initializing pairing page:', error);
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;
if (errorMessage.includes('PBKDF2') || errorMessage.includes('security')) {
console.log('⚠️ Security error detected, redirecting to security-setup...');
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...');
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...');
setTimeout(() => {
window.location.href = '/src/pages/birthday-setup/birthday-setup.html';
}, 2000);
}
} finally {
isInitializing = false;
}
});

View File

@ -20,6 +20,7 @@ const routes: { [key: string]: string } = {
'wallet-setup': '/src/pages/wallet-setup/wallet-setup.html',
'birthday-setup': '/src/pages/birthday-setup/birthday-setup.html',
'block-sync': '/src/pages/block-sync/block-sync.html',
'pairing': '/src/pages/pairing/pairing.html',
};
export let currentRoute = '';
@ -63,9 +64,8 @@ export async function checkStorageStateAndNavigate(): Promise<void> {
// Vérifier si la date anniversaire est configurée (wallet avec birthday > 0)
if (device.sp_wallet.birthday && device.sp_wallet.birthday > 0) {
console.log('🎂 Birthday is configured, navigating to pairing');
// Ne pas vérifier le pairing ici pour éviter d'initialiser WebAssembly
// La page home.ts vérifiera le pairing si nécessaire
await navigate('home');
// Rediriger vers la page de pairing standalone
await navigate('pairing');
return;
}
@ -111,7 +111,7 @@ async function handleLocation(path: string) {
console.log('📍 Route HTML:', routeHtml);
// Pour les pages de setup, rediriger directement vers la page HTML
if (path === 'security-setup' || path === 'wallet-setup' || path === 'birthday-setup' || path === 'block-sync') {
if (path === 'security-setup' || path === 'wallet-setup' || path === 'birthday-setup' || path === 'block-sync' || path === 'pairing') {
console.log('📍 Processing setup route:', path);
window.location.href = routeHtml;
return;