sunuid-sdk 1.0.50 → 1.0.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,251 @@
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Test Nom Partenaire - SunuID SDK</title>
7
+ <style>
8
+ body {
9
+ font-family: Arial, sans-serif;
10
+ max-width: 800px;
11
+ margin: 0 auto;
12
+ padding: 20px;
13
+ background-color: #f5f5f5;
14
+ }
15
+ .container {
16
+ background: white;
17
+ padding: 30px;
18
+ border-radius: 10px;
19
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
20
+ }
21
+ .test-section {
22
+ margin: 20px 0;
23
+ padding: 15px;
24
+ border: 1px solid #ddd;
25
+ border-radius: 5px;
26
+ }
27
+ .success { border-color: #4CAF50; background-color: #f1f8e9; }
28
+ .error { border-color: #f44336; background-color: #ffebee; }
29
+ .info { border-color: #2196F3; background-color: #e3f2fd; }
30
+ button {
31
+ background: #2196F3;
32
+ color: white;
33
+ border: none;
34
+ padding: 10px 20px;
35
+ border-radius: 5px;
36
+ cursor: pointer;
37
+ margin: 5px;
38
+ }
39
+ button:hover { background: #1976D2; }
40
+ .log {
41
+ background: #f5f5f5;
42
+ padding: 10px;
43
+ border-radius: 5px;
44
+ font-family: monospace;
45
+ font-size: 12px;
46
+ max-height: 200px;
47
+ overflow-y: auto;
48
+ }
49
+ .partner-name {
50
+ font-weight: bold;
51
+ color: #2196F3;
52
+ }
53
+ </style>
54
+ </head>
55
+ <body>
56
+ <div class="container">
57
+ <h1>🏷️ Test Nom Partenaire - SunuID SDK</h1>
58
+
59
+ <div class="test-section info">
60
+ <h3>📋 Informations</h3>
61
+ <p>Ce test vérifie que le nom du partenaire s'affiche correctement dans les labels et textes au lieu d'être codé en dur.</p>
62
+ </div>
63
+
64
+ <div class="test-section">
65
+ <h3>🔧 Configuration</h3>
66
+ <p><strong>Nom du partenaire configuré:</strong> <span class="partner-name" id="partner-name">Chargement...</span></p>
67
+ <p><strong>Type de service:</strong> <span id="service-type">Chargement...</span></p>
68
+ </div>
69
+
70
+ <div class="test-section">
71
+ <h3>🧪 Tests</h3>
72
+ <button onclick="testPartnerName()">Test Nom Partenaire</button>
73
+ <button onclick="testQRGeneration()">Test Génération QR</button>
74
+ <button onclick="clearLogs()">Effacer Logs</button>
75
+ </div>
76
+
77
+ <div class="test-section">
78
+ <h3>📊 Logs</h3>
79
+ <div id="logs" class="log"></div>
80
+ </div>
81
+
82
+ <div id="qr-container" class="test-section">
83
+ <h3>📱 QR Code</h3>
84
+ <p>Le QR code apparaîtra ici après le test de génération.</p>
85
+ </div>
86
+
87
+ <div class="test-section">
88
+ <h3>🔍 Vérifications</h3>
89
+ <div id="checks">
90
+ <p>✅ Instructions: <span id="instructions-check">En attente...</span></p>
91
+ <p>✅ Alt text: <span id="alt-check">En attente...</span></p>
92
+ <p>✅ Label QR: <span id="label-check">En attente...</span></p>
93
+ </div>
94
+ </div>
95
+ </div>
96
+
97
+ <!-- Configuration -->
98
+ <script>
99
+ // Configuration avec nom de partenaire personnalisé
100
+ window.SunuIDConfig = {
101
+ apiUrl: 'https://api.sunuid.fayma.sn',
102
+ endpoints: {
103
+ qrGenerate: '/qr-generate',
104
+ qrStatus: '/qr-status',
105
+ qrConfirm: '/qr-confirm'
106
+ }
107
+ };
108
+ </script>
109
+
110
+ <!-- SDK -->
111
+ <script src="../src/sunuid-sdk.js"></script>
112
+
113
+ <script>
114
+ let sunuid;
115
+ let logs = [];
116
+
117
+ function log(message, type = 'info') {
118
+ const timestamp = new Date().toLocaleTimeString();
119
+ const logEntry = `[${timestamp}] ${message}`;
120
+ logs.push(logEntry);
121
+
122
+ const logsDiv = document.getElementById('logs');
123
+ logsDiv.innerHTML = logs.join('\n');
124
+ logsDiv.scrollTop = logsDiv.scrollHeight;
125
+
126
+ console.log(logEntry);
127
+ }
128
+
129
+ function clearLogs() {
130
+ logs = [];
131
+ document.getElementById('logs').innerHTML = '';
132
+ }
133
+
134
+ function updateConfigDisplay() {
135
+ document.getElementById('partner-name').textContent = 'Ma Banque';
136
+ document.getElementById('service-type').textContent = 'Authentification (Type 2)';
137
+ }
138
+
139
+ async function testPartnerName() {
140
+ log('🧪 Début du test du nom du partenaire...');
141
+
142
+ try {
143
+ // Initialiser le SDK avec un nom de partenaire personnalisé
144
+ sunuid = new SunuID({
145
+ clientId: 'test_client',
146
+ secretId: 'test_secret',
147
+ type: 2,
148
+ partnerName: 'Ma Banque', // Nom personnalisé
149
+ theme: 'light'
150
+ });
151
+
152
+ log('✅ SDK initialisé avec succès');
153
+ log(`🏷️ Nom du partenaire configuré: ${sunuid.config.partnerName}`);
154
+
155
+ // Vérifier que le nom du partenaire est correct
156
+ if (sunuid.config.partnerName !== 'Ma Banque') {
157
+ throw new Error('❌ Le nom du partenaire n\'est pas correctement configuré!');
158
+ }
159
+
160
+ log('✅ Nom du partenaire correctement configuré');
161
+
162
+ document.querySelector('.test-section:nth-child(3)').className = 'test-section success';
163
+
164
+ } catch (error) {
165
+ log(`❌ Erreur: ${error.message}`, 'error');
166
+ document.querySelector('.test-section:nth-child(3)').className = 'test-section error';
167
+ }
168
+ }
169
+
170
+ async function testQRGeneration() {
171
+ log('🧪 Test de génération de QR avec nom personnalisé...');
172
+
173
+ try {
174
+ if (!sunuid) {
175
+ throw new Error('SDK non initialisé. Lancez d\'abord le test de configuration.');
176
+ }
177
+
178
+ // Simuler la génération d'un QR code pour vérifier les textes
179
+ const container = document.getElementById('qr-container');
180
+
181
+ // Créer un élément temporaire pour tester les textes
182
+ const tempDiv = document.createElement('div');
183
+ tempDiv.innerHTML = `
184
+ <div class="sunuid-qr-instructions" style="display: none;">
185
+ <p>Scannez ce QR code avec l'application ${sunuid.config.partnerName} pour vous connecter</p>
186
+ </div>
187
+ <div class="sunuid-qr-ready" style="text-align: center; padding: 20px;">
188
+ <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==" alt="QR Code ${sunuid.config.partnerName}" style="max-width: 300px; border: 2px solid #ddd; border-radius: 10px;">
189
+ </div>
190
+ `;
191
+
192
+ // Vérifier les textes
193
+ const instructions = tempDiv.querySelector('.sunuid-qr-instructions p').textContent;
194
+ const altText = tempDiv.querySelector('img').alt;
195
+
196
+ log(`📝 Instructions: ${instructions}`);
197
+ log(`🏷️ Alt text: ${altText}`);
198
+
199
+ // Vérifications
200
+ const instructionsCheck = document.getElementById('instructions-check');
201
+ const altCheck = document.getElementById('alt-check');
202
+ const labelCheck = document.getElementById('label-check');
203
+
204
+ if (instructions.includes('Ma Banque')) {
205
+ instructionsCheck.textContent = '✅ Correct';
206
+ instructionsCheck.style.color = 'green';
207
+ } else {
208
+ instructionsCheck.textContent = '❌ Incorrect';
209
+ instructionsCheck.style.color = 'red';
210
+ }
211
+
212
+ if (altText.includes('Ma Banque')) {
213
+ altCheck.textContent = '✅ Correct';
214
+ altCheck.style.color = 'green';
215
+ } else {
216
+ altCheck.textContent = '❌ Incorrect';
217
+ altCheck.style.color = 'red';
218
+ }
219
+
220
+ // Simuler le label du QR code
221
+ const typeName = sunuid.getTypeName ? sunuid.getTypeName(2) : 'Authentification';
222
+ const qrLabel = `${typeName} - ${sunuid.config.partnerName}`;
223
+ log(`🏷️ Label QR simulé: ${qrLabel}`);
224
+
225
+ if (qrLabel.includes('Ma Banque')) {
226
+ labelCheck.textContent = '✅ Correct';
227
+ labelCheck.style.color = 'green';
228
+ } else {
229
+ labelCheck.textContent = '❌ Incorrect';
230
+ labelCheck.style.color = 'red';
231
+ }
232
+
233
+ log('✅ Test de génération de QR terminé');
234
+
235
+ document.querySelector('.test-section:nth-child(4)').className = 'test-section success';
236
+
237
+ } catch (error) {
238
+ log(`❌ Erreur: ${error.message}`, 'error');
239
+ document.querySelector('.test-section:nth-child(4)').className = 'test-section error';
240
+ }
241
+ }
242
+
243
+ // Initialisation
244
+ document.addEventListener('DOMContentLoaded', function() {
245
+ log('🚀 Page chargée');
246
+ updateConfigDisplay();
247
+ log('📋 Configuration affichée');
248
+ });
249
+ </script>
250
+ </body>
251
+ </html>
@@ -0,0 +1,200 @@
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Test Configuration Production - SunuID SDK</title>
7
+ <style>
8
+ body {
9
+ font-family: Arial, sans-serif;
10
+ max-width: 800px;
11
+ margin: 0 auto;
12
+ padding: 20px;
13
+ background-color: #f5f5f5;
14
+ }
15
+ .container {
16
+ background: white;
17
+ padding: 30px;
18
+ border-radius: 10px;
19
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
20
+ }
21
+ .test-section {
22
+ margin: 20px 0;
23
+ padding: 15px;
24
+ border: 1px solid #ddd;
25
+ border-radius: 5px;
26
+ }
27
+ .success { border-color: #4CAF50; background-color: #f1f8e9; }
28
+ .error { border-color: #f44336; background-color: #ffebee; }
29
+ .info { border-color: #2196F3; background-color: #e3f2fd; }
30
+ button {
31
+ background: #2196F3;
32
+ color: white;
33
+ border: none;
34
+ padding: 10px 20px;
35
+ border-radius: 5px;
36
+ cursor: pointer;
37
+ margin: 5px;
38
+ }
39
+ button:hover { background: #1976D2; }
40
+ .log {
41
+ background: #f5f5f5;
42
+ padding: 10px;
43
+ border-radius: 5px;
44
+ font-family: monospace;
45
+ font-size: 12px;
46
+ max-height: 200px;
47
+ overflow-y: auto;
48
+ }
49
+ </style>
50
+ </head>
51
+ <body>
52
+ <div class="container">
53
+ <h1>🧪 Test Configuration Production - SunuID SDK</h1>
54
+
55
+ <div class="test-section info">
56
+ <h3>📋 Informations</h3>
57
+ <p>Ce test vérifie que le SDK utilise correctement les URLs de production au lieu des URLs locales.</p>
58
+ </div>
59
+
60
+ <div class="test-section">
61
+ <h3>🔧 Configuration</h3>
62
+ <p><strong>API URL:</strong> <span id="api-url">Chargement...</span></p>
63
+ <p><strong>QR Generator URL:</strong> <span id="qr-url">Chargement...</span></p>
64
+ <p><strong>Secure Init URL:</strong> <span id="secure-url">Chargement...</span></p>
65
+ </div>
66
+
67
+ <div class="test-section">
68
+ <h3>🧪 Tests</h3>
69
+ <button onclick="testConfiguration()">Test Configuration</button>
70
+ <button onclick="testQRGeneration()">Test Génération QR</button>
71
+ <button onclick="clearLogs()">Effacer Logs</button>
72
+ </div>
73
+
74
+ <div class="test-section">
75
+ <h3>📊 Logs</h3>
76
+ <div id="logs" class="log"></div>
77
+ </div>
78
+
79
+ <div id="qr-container" class="test-section">
80
+ <h3>📱 QR Code</h3>
81
+ <p>Le QR code apparaîtra ici après le test de génération.</p>
82
+ </div>
83
+ </div>
84
+
85
+ <!-- Configuration -->
86
+ <script>
87
+ // Configuration pour la production
88
+ window.SunuIDConfig = {
89
+ apiUrl: 'https://api.sunuid.fayma.sn',
90
+ endpoints: {
91
+ qrGenerate: '/qr-generate',
92
+ qrStatus: '/qr-status',
93
+ qrConfirm: '/qr-confirm'
94
+ }
95
+ };
96
+ </script>
97
+
98
+ <!-- SDK -->
99
+ <script src="../src/sunuid-sdk.js"></script>
100
+
101
+ <script>
102
+ let sunuid;
103
+ let logs = [];
104
+
105
+ function log(message, type = 'info') {
106
+ const timestamp = new Date().toLocaleTimeString();
107
+ const logEntry = `[${timestamp}] ${message}`;
108
+ logs.push(logEntry);
109
+
110
+ const logsDiv = document.getElementById('logs');
111
+ logsDiv.innerHTML = logs.join('\n');
112
+ logsDiv.scrollTop = logsDiv.scrollHeight;
113
+
114
+ console.log(logEntry);
115
+ }
116
+
117
+ function clearLogs() {
118
+ logs = [];
119
+ document.getElementById('logs').innerHTML = '';
120
+ }
121
+
122
+ function updateConfigDisplay() {
123
+ document.getElementById('api-url').textContent = window.SunuIDConfig.apiUrl;
124
+ document.getElementById('qr-url').textContent = window.SunuIDConfig.apiUrl.replace('/api', '') + '/qr-generator.php';
125
+ document.getElementById('secure-url').textContent = window.SunuIDConfig.apiUrl.replace('/api', '') + '/secure-init.php';
126
+ }
127
+
128
+ async function testConfiguration() {
129
+ log('🧪 Début du test de configuration...');
130
+
131
+ try {
132
+ // Initialiser le SDK
133
+ sunuid = new SunuID({
134
+ clientId: 'test_client',
135
+ secretId: 'test_secret',
136
+ type: 2,
137
+ partnerName: 'Test Production',
138
+ theme: 'light'
139
+ });
140
+
141
+ log('✅ SDK initialisé avec succès');
142
+ log(`📡 API URL configurée: ${sunuid.config.apiUrl}`);
143
+ log(`🔐 Secure Init URL: ${sunuid.config.secureInitUrl}`);
144
+
145
+ // Vérifier que les URLs ne sont pas locales
146
+ if (sunuid.config.apiUrl.includes('localhost')) {
147
+ throw new Error('❌ L\'API URL est encore locale!');
148
+ }
149
+ if (sunuid.config.secureInitUrl.includes('localhost')) {
150
+ throw new Error('❌ Le Secure Init URL est encore local!');
151
+ }
152
+
153
+ log('✅ Configuration de production détectée');
154
+
155
+ document.querySelector('.test-section:nth-child(3)').className = 'test-section success';
156
+
157
+ } catch (error) {
158
+ log(`❌ Erreur: ${error.message}`, 'error');
159
+ document.querySelector('.test-section:nth-child(3)').className = 'test-section error';
160
+ }
161
+ }
162
+
163
+ async function testQRGeneration() {
164
+ log('🧪 Test de génération de QR...');
165
+
166
+ try {
167
+ if (!sunuid) {
168
+ throw new Error('SDK non initialisé. Lancez d\'abord le test de configuration.');
169
+ }
170
+
171
+ // Vérifier que l'URL de génération QR n'est pas locale
172
+ const qrGeneratorUrl = sunuid.config.apiUrl.replace('/api', '') + '/qr-generator.php';
173
+ log(`📡 URL QR Generator: ${qrGeneratorUrl}`);
174
+
175
+ if (qrGeneratorUrl.includes('localhost')) {
176
+ throw new Error('❌ L\'URL QR Generator est encore locale!');
177
+ }
178
+
179
+ log('✅ URL QR Generator correcte pour la production');
180
+
181
+ // Note: On ne fait pas de vraie requête car c'est un test
182
+ log('ℹ️ Test de génération simulé (pas de vraie requête)');
183
+
184
+ document.querySelector('.test-section:nth-child(4)').className = 'test-section success';
185
+
186
+ } catch (error) {
187
+ log(`❌ Erreur: ${error.message}`, 'error');
188
+ document.querySelector('.test-section:nth-child(4)').className = 'test-section error';
189
+ }
190
+ }
191
+
192
+ // Initialisation
193
+ document.addEventListener('DOMContentLoaded', function() {
194
+ log('🚀 Page chargée');
195
+ updateConfigDisplay();
196
+ log('📋 Configuration affichée');
197
+ });
198
+ </script>
199
+ </body>
200
+ </html>
@@ -0,0 +1,199 @@
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Vérification KYC - Universel</title>
7
+ <style>
8
+ body {
9
+ font-family: Arial, sans-serif;
10
+ display: flex;
11
+ justify-content: center;
12
+ align-items: center;
13
+ min-height: 100vh;
14
+ margin: 0;
15
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
16
+ }
17
+ .kyc-card {
18
+ background: white;
19
+ padding: 40px;
20
+ border-radius: 15px;
21
+ box-shadow: 0 10px 30px rgba(0,0,0,0.2);
22
+ text-align: center;
23
+ max-width: 400px;
24
+ }
25
+ .qr-code {
26
+ margin: 20px 0;
27
+ }
28
+ .qr-code img {
29
+ max-width: 100%;
30
+ height: auto;
31
+ }
32
+ .status {
33
+ margin-top: 20px;
34
+ padding: 10px;
35
+ border-radius: 5px;
36
+ }
37
+ .status.loading {
38
+ background: #e3f2fd;
39
+ color: #1976d2;
40
+ }
41
+ .status.success {
42
+ background: #e8f5e8;
43
+ color: #2e7d32;
44
+ }
45
+ .status.error {
46
+ background: #ffebee;
47
+ color: #c62828;
48
+ }
49
+ .logo {
50
+ width: 80px;
51
+ height: 80px;
52
+ margin: 0 auto 20px;
53
+ background: #f093fb;
54
+ border-radius: 50%;
55
+ display: flex;
56
+ align-items: center;
57
+ justify-content: center;
58
+ font-size: 40px;
59
+ color: white;
60
+ }
61
+ .download-link {
62
+ margin-top: 20px;
63
+ padding: 10px 20px;
64
+ background: #f093fb;
65
+ color: white;
66
+ text-decoration: none;
67
+ border-radius: 25px;
68
+ display: inline-block;
69
+ transition: background 0.3s;
70
+ }
71
+ .download-link:hover {
72
+ background: #e085e8;
73
+ }
74
+ .steps {
75
+ text-align: left;
76
+ margin: 20px 0;
77
+ padding: 15px;
78
+ background: #f8f9fa;
79
+ border-radius: 10px;
80
+ }
81
+ .step {
82
+ margin: 10px 0;
83
+ display: flex;
84
+ align-items: center;
85
+ }
86
+ .step-number {
87
+ width: 25px;
88
+ height: 25px;
89
+ background: #f093fb;
90
+ color: white;
91
+ border-radius: 50%;
92
+ display: flex;
93
+ align-items: center;
94
+ justify-content: center;
95
+ font-size: 12px;
96
+ font-weight: bold;
97
+ margin-right: 10px;
98
+ }
99
+ </style>
100
+ </head>
101
+ <body>
102
+ <div class="kyc-card">
103
+ <div class="logo">📋</div>
104
+ <h1>Vérification KYC</h1>
105
+ <p>Scannez le QR code pour vérifier votre identité</p>
106
+
107
+ <div class="steps">
108
+ <div class="step">
109
+ <div class="step-number">1</div>
110
+ <span>Scannez le QR code avec SunuID</span>
111
+ </div>
112
+ <div class="step">
113
+ <div class="step-number">2</div>
114
+ <span>Suivez les instructions dans l'app</span>
115
+ </div>
116
+ <div class="step">
117
+ <div class="step-number">3</div>
118
+ <span>Votre identité sera vérifiée</span>
119
+ </div>
120
+ </div>
121
+
122
+ <div id="qr-container" class="qr-code">
123
+ <div class="status loading">⏳ Génération du QR code...</div>
124
+ </div>
125
+
126
+ <div id="status" class="status loading">
127
+ ⏳ En attente de la vérification...
128
+ </div>
129
+
130
+ <a href="https://sunuid.sn/download" target="_blank" class="download-link">
131
+ 📱 Télécharger SunuID
132
+ </a>
133
+ </div>
134
+
135
+ <!-- SunuID SDK -->
136
+ <script src="https://cdn.jsdelivr.net/npm/@sunuid/sdk@latest/dist/sunuid-sdk.min.js"></script>
137
+
138
+ <!-- QRCode library pour le fallback côté client -->
139
+ <script src="https://cdn.jsdelivr.net/npm/qrcode@1.5.3/lib/browser.min.js"></script>
140
+
141
+ <script>
142
+ // Configuration KYC - REMPLACEZ PAR VOS VALEURS
143
+ const config = {
144
+ client_id: 'VOTRE_CLIENT_ID', // ← Remplacez par votre CLIENT_ID
145
+ secret_id: 'VOTRE_SECRET_ID', // ← Remplacez par votre SECRET_ID
146
+ type: 1, // ← 1=KYC, 2=AUTH, 3=Signature
147
+ partner_name: 'Votre Entreprise', // ← Remplacez par votre nom
148
+ options: {
149
+ kyc_type: 'full',
150
+ required_fields: ['identity', 'address', 'phone'],
151
+ redirect_url: 'https://votre-site.com/kyc-complete'
152
+ }
153
+ };
154
+
155
+ // Initialiser SunuID
156
+ const sunuid = new SunuID(config);
157
+
158
+ // Démarrer automatiquement
159
+ sunuid.init().then(() => {
160
+ console.log('✅ SunuID KYC initialisé !');
161
+ document.getElementById('qr-container').innerHTML =
162
+ '<img src="' + sunuid.getQRCode() + '" alt="QR Code KYC SunuID">';
163
+ }).catch(error => {
164
+ console.error('❌ Erreur:', error);
165
+ document.getElementById('status').className = 'status error';
166
+ document.getElementById('status').innerHTML = '❌ Erreur de connexion: ' + error.message;
167
+ });
168
+
169
+ // Écouter les événements KYC
170
+ sunuid.on('kyc_completed', (kycData) => {
171
+ console.log('📋 KYC terminé:', kycData);
172
+ document.getElementById('status').className = 'status success';
173
+ document.getElementById('status').innerHTML = '✅ Vérification KYC réussie ! Redirection...';
174
+
175
+ // Redirection après 2 secondes
176
+ setTimeout(() => {
177
+ window.location.href = '/kyc-complete'; // ← Remplacez par votre URL
178
+ }, 2000);
179
+ });
180
+
181
+ sunuid.on('kyc_progress', (progress) => {
182
+ console.log('📊 Progression KYC:', progress);
183
+ document.getElementById('status').className = 'status loading';
184
+ document.getElementById('status').innerHTML = '📊 Vérification en cours... ' + progress.step;
185
+ });
186
+
187
+ sunuid.on('error', (error) => {
188
+ console.error('❌ Erreur:', error);
189
+ document.getElementById('status').className = 'status error';
190
+ document.getElementById('status').innerHTML = '❌ Erreur: ' + error.message;
191
+ });
192
+
193
+ sunuid.on('expired', () => {
194
+ document.getElementById('status').className = 'status error';
195
+ document.getElementById('status').innerHTML = '⏰ QR expiré. Actualisez la page.';
196
+ });
197
+ </script>
198
+ </body>
199
+ </html>