ci: docker_tag=cleanup Nettoyage des composants inutiles

- Suppression du composant header (plus utilisé)
- Suppression du dossier modal générique
- Suppression de validation-rule-modal (non utilisé)
- Nettoyage des imports et références inutiles
- Suppression des méthodes d'injection de modales obsolètes
- Conservation des composants essentiels: account-nav, device-management, iframe-pairing, login-modal, secure-credentials, validation-modal
This commit is contained in:
NicolasCantu 2025-10-23 13:05:36 +02:00
parent 530dcaf633
commit b545e3875e
13 changed files with 8 additions and 525 deletions

View File

@ -1,49 +0,0 @@
<div class="nav-wrapper">
<div id="profile-header-container"></div>
<div class="brand-logo">4NK</div>
<div class="nav-right-icons">
<div class="notification-container">
<div class="bell-icon">
<svg
class="notification-bell"
onclick="openCloseNotifications()"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512"
>
<path
d="M224 0c-17.7 0-32 14.3-32 32V51.2C119 66 64 130.6 64 208v25.4c0 45.4-15.5 89.5-43.8 124.9L5.3 377c-5.8 7.2-6.9 17.1-2.9 25.4S14.8 416 24 416H424c9.2 0 17.6-5.3 21.6-13.6s2.9-18.2-2.9-25.4l-14.9-18.6C399.5 322.9 384 278.8 384 233.4V208c0-77.4-55-142-128-156.8V32c0-17.7-14.3-32-32-32zm0 96c61.9 0 112 50.1 112 112v25.4c0 47.9 13.9 94.6 39.7 134.6H72.3C98.1 328 112 281.3 112 233.4V208c0-61.9 50.1-112 112-112zm64 352H224 160c0 17 6.7 33.3 18.7 45.3s28.3 18.7 45.3 18.7s33.3-6.7 45.3-18.7s18.7-28.3 18.7-45.3z"
/>
</svg>
</div>
<div class="notification-badge"></div>
<div id="notification-board" class="notification-board">
<div class="no-notification">No notifications available</div>
</div>
</div>
<div class="burger-menu">
<svg
class="burger-menu"
onclick="toggleMenu()"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512"
>
<path
d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"
/>
</svg>
<div class="menu-content" id="menu">
<!-- <a onclick="unpair()">Revoke</a> -->
<a onclick="importJSON()">Import</a>
<a onclick="createBackUp()">Export</a>
<a onclick="navigate('account')">Account</a>
<a onclick="navigate('chat')">Chat</a>
<a onclick="navigate('signature')">Signatures</a>
<a onclick="navigate('process')">Process</a>
<a onclick="disconnect()">Disconnect</a>
<a onclick="deleteAccount()" class="delete-account-btn">🗑️ Supprimer</a>
</div>
</div>
</div>
</div>

View File

@ -1,221 +0,0 @@
import ModalService from '~/services/modal.service';
// import { INotification } from '../../models/notification.model'; // Unused import
import { currentRoute, navigate } from '../../router';
import Services from '../../services/service';
import { BackUp } from '~/models/backup.model';
let notifications = [];
export async function unpair() {
const service = await Services.getInstance();
await service.unpairDevice();
await navigate('home');
}
(window as any).unpair = unpair;
function toggleMenu() {
const menu = document.getElementById('menu');
if (menu) {
if (menu.style.display === 'block') {
menu.style.display = 'none';
} else {
menu.style.display = 'block';
}
}
}
(window as any).toggleMenu = toggleMenu;
async function _getNotifications() {
const service = await Services.getInstance();
notifications = service.getNotifications() || [];
return notifications;
}
function openCloseNotifications() {
const notifications = document.querySelector('.notification-board') as HTMLDivElement;
notifications.style.display = notifications?.style.display === 'none' ? 'block' : 'none';
}
(window as any).openCloseNotifications = openCloseNotifications;
export async function initHeader() {
if (currentRoute === 'account') {
// Charger le profile-header
const profileContainer = document.getElementById('profile-header-container');
if (profileContainer) {
const profileHeaderHtml = await fetch(
'/src/components/profile-header/profile-header.html'
).then(res => res.text());
profileContainer.innerHTML = profileHeaderHtml;
// Initialiser les données du profil
loadUserProfile();
}
}
if (currentRoute === 'home') {
hideSomeFunctionnalities();
} else {
fetchNotifications();
setInterval(fetchNotifications, 2 * 60 * 1000);
}
}
function hideSomeFunctionnalities() {
const bell = document.querySelector('.bell-icon') as HTMLDivElement;
if (bell) bell.style.display = 'none';
const notifBadge = document.querySelector('.notification-badge') as HTMLDivElement;
if (notifBadge) notifBadge.style.display = 'none';
const actions = document.querySelectorAll('.menu-content a') as NodeListOf<HTMLAnchorElement>;
const excludedActions = ['Import', 'Export'];
for (const action of actions) {
if (!excludedActions.includes(action.innerHTML)) {
action.style.display = 'none';
}
}
}
async function setNotification(notifications: any[]): Promise<void> {
const badge = document.querySelector('.notification-badge') as HTMLDivElement;
const noNotifications = document.querySelector('.no-notification') as HTMLDivElement;
if (notifications?.length) {
badge.innerText = notifications.length.toString();
const notificationBoard = document.querySelector('.notification-board') as HTMLDivElement;
notificationBoard.querySelectorAll('.notification-element')?.forEach(elem => elem.remove());
noNotifications.style.display = 'none';
for (const notif of notifications) {
const notifElement = document.createElement('div');
notifElement.className = 'notification-element';
notifElement.setAttribute('notif-id', notif.processId);
notifElement.innerHTML = `
<div>Validation required : </div>
<div style="text-overflow: ellipsis; content-visibility: auto;">${notif.processId}</div>
`;
// this.addSubscription(notifElement, 'click', 'goToProcessPage')
notificationBoard.appendChild(notifElement);
notifElement.addEventListener('click', async () => {
const modalService = await ModalService.getInstance();
modalService.injectValidationModal(notif);
});
}
} else {
noNotifications.style.display = 'block';
}
}
async function fetchNotifications() {
const service = await Services.getInstance();
const data = service.getNotifications() || [];
await setNotification(data);
}
async function loadUserProfile() {
// Charger les données du profil depuis le localStorage
const userName = localStorage.getItem('userName');
const userLastName = localStorage.getItem('userLastName');
const userAvatar = localStorage.getItem('userAvatar') || 'https://via.placeholder.com/150';
const userBanner = localStorage.getItem('userBanner') || 'https://via.placeholder.com/800x200';
// Mettre à jour les éléments du DOM
const nameElement = document.querySelector('.user-name');
const lastNameElement = document.querySelector('.user-lastname');
const avatarElement = document.querySelector('.avatar');
const bannerElement = document.querySelector('.banner-image');
if (nameElement) nameElement.textContent = userName;
if (lastNameElement) lastNameElement.textContent = userLastName;
if (avatarElement) (avatarElement as HTMLImageElement).src = userAvatar;
if (bannerElement) (bannerElement as HTMLImageElement).src = userBanner;
}
export async function importJSON() {
const input = document.createElement('input');
input.type = 'file';
input.accept = '.json';
input.onchange = async e => {
const file = (e.target as HTMLInputElement).files?.[0];
if (file) {
const reader = new FileReader();
reader.onload = async e => {
try {
const content: BackUp = JSON.parse(e.target?.result as string);
const service = await Services.getInstance();
await service.importJSON(content);
alert('Import réussi');
window.location.reload();
} catch (error) {
alert("Erreur lors de l'import: " + error);
}
};
reader.readAsText(file);
}
};
input.click();
}
(window as any).importJSON = importJSON;
export async function createBackUp() {
const service = await Services.getInstance();
const backUp = await service.createBackUp();
if (!backUp) {
console.error('No device to backup');
return;
}
try {
const backUpJson = JSON.stringify(backUp, null, 2);
const blob = new Blob([backUpJson], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = '4nk-backup.json';
a.click();
URL.revokeObjectURL(url);
console.log('Backup successfully prepared for download');
} catch (e) {
console.error(e);
}
}
(window as any).createBackUp = createBackUp;
export async function disconnect() {
console.log('Disconnecting...');
try {
localStorage.clear();
await new Promise<void>((resolve, reject) => {
const request = indexedDB.deleteDatabase('4nk');
request.onsuccess = () => {
console.log('IndexedDB deleted successfully');
resolve();
};
request.onerror = () => reject(request.error);
request.onblocked = () => {
console.log('Database deletion was blocked');
resolve();
};
});
const registrations = await navigator.serviceWorker.getRegistrations();
await Promise.all(registrations.map(registration => registration.unregister()));
console.log('Service worker unregistered');
await navigate('home');
setTimeout(() => {
window.location.href = window.location.origin;
}, 100);
} catch (error) {
console.error('Error during disconnect:', error);
// force reload
window.location.href = window.location.origin;
}
}
(window as any).disconnect = disconnect;

View File

@ -1,16 +0,0 @@
<div id="modal" class="modal">
<div class="modal-content">
<div class="modal-title">Login</div>
<div class="message">
Do you want to pair device?<br />
Attempting to pair device with address <br />
<strong>{{device1}}</strong> <br />
with device with address <br />
<strong>{{device2}}</strong>
</div>
<div class="confirmation-box">
<a class="btn confirmation-btn" onclick="confirm()">Confirm</a>
<a class="btn refusal-btn" onclick="closeConfirmationModal()">Refuse</a>
</div>
</div>
</div>

View File

@ -1,13 +0,0 @@
import ModalService from '../../services/modal.service';
const modalService = await ModalService.getInstance();
// export async function confirm() {
// modalService.confirmPairing();
// }
export async function closeConfirmationModal() {
modalService.closeConfirmationModal();
}
(window as any).confirm = confirm;
(window as any).closeConfirmationModal = closeConfirmationModal;

View File

@ -1,14 +0,0 @@
<div id="creation-modal" class="modal">
<div class="modal-content">
<div class="modal-title">Login</div>
<div class="message">
Do you want to create a 4NK member?<br />
Attempting to create a member with address <br />
<strong>{{device1}}</strong> <br />
</div>
<div class="confirmation-box">
<a class="btn confirmation-btn" onclick="confirm()">Confirm</a>
<a class="btn refusal-btn" onclick="closeConfirmationModal()">Refuse</a>
</div>
</div>
</div>

View File

@ -1,6 +0,0 @@
<div id="waiting-modal" class="modal">
<div class="modal-content">
<div class="modal-title">Login</div>
<div class="message">Waiting for Device 2...</div>
</div>
</div>

View File

@ -1,4 +1,4 @@
import ModalService from '~/services/modal.service';
import ModalService from '../../services/modal.service';
async function validate() {
console.log('==> VALIDATE');

View File

@ -1,72 +0,0 @@
<div
id="validation-rule-modal"
style="
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: none;
justify-content: center;
align-items: center;
z-index: 9999;
"
>
<div
style="
background: white;
padding: 2rem;
border-radius: 0.5rem;
width: 400px;
max-width: 90%;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
"
>
<h2 style="font-size: 1.2rem; font-weight: bold; margin-bottom: 1rem">Add Validation Rule</h2>
<label style="display: block; margin-bottom: 0.5rem">
Quorum:
<input
id="vr-quorum"
type="number"
style="width: 100%; padding: 0.5rem; margin-top: 0.25rem"
/>
</label>
<label style="display: block; margin-bottom: 0.5rem">
Min Sig Member:
<input
id="vr-minsig"
type="number"
style="width: 100%; padding: 0.5rem; margin-top: 0.25rem"
/>
</label>
<label style="display: block; margin-bottom: 1rem">
Fields (comma-separated):
<input
id="vr-fields"
type="text"
placeholder="e.g. field1, field2"
style="width: 100%; padding: 0.5rem; margin-top: 0.25rem"
/>
</label>
<div style="display: flex; justify-content: flex-end; gap: 1rem">
<button id="vr-cancel" style="padding: 0.5rem 1rem">Cancel</button>
<button
id="vr-submit"
style="
padding: 0.5rem 1rem;
background-color: #4f46e5;
color: white;
border: none;
border-radius: 0.375rem;
"
>
Add
</button>
</div>
</div>
</div>

View File

@ -1,66 +0,0 @@
export interface ValidationRule {
quorum: number;
fields: string[];
min_sig_member: number;
}
/**
* Loads and injects the modal HTML into the document if not already loaded.
*/
export async function loadValidationRuleModal(
templatePath: string = '/src/components/validation-rule-modal/validation-rule-modal.html'
) {
if (document.getElementById('validation-rule-modal')) return;
const res = await fetch(templatePath);
const html = await res.text();
const tempDiv = document.createElement('div');
tempDiv.innerHTML = html;
const modal = tempDiv.querySelector('#validation-rule-modal');
if (!modal) {
throw new Error('Modal HTML missing #validation-rule-modal');
}
document.body.appendChild(modal);
}
/**
* Opens the modal and lets the user input a ValidationRule.
* Calls the callback with the constructed rule on submit.
*/
export function showValidationRuleModal(onSubmit: (rule: ValidationRule) => void) {
const modal = document.getElementById('validation-rule-modal')!;
const quorumInput = document.getElementById('vr-quorum') as HTMLInputElement;
const minsigInput = document.getElementById('vr-minsig') as HTMLInputElement;
const fieldsInput = document.getElementById('vr-fields') as HTMLInputElement;
const cancelBtn = document.getElementById('vr-cancel')!;
const submitBtn = document.getElementById('vr-submit')!;
// Reset values
quorumInput.value = '';
minsigInput.value = '';
fieldsInput.value = '';
modal.style.display = 'flex';
cancelBtn.onclick = () => {
modal.style.display = 'none';
};
submitBtn.onclick = () => {
const rule: ValidationRule = {
quorum: parseInt(quorumInput.value),
min_sig_member: parseInt(minsigInput.value),
fields: fieldsInput.value
.split(',')
.map(f => f.trim())
.filter(Boolean),
};
modal.style.display = 'none';
onSubmit(rule);
};
}

View File

@ -1,4 +1,4 @@
import { DocumentSignature } from '~/models/signature.models';
import { DocumentSignature } from '../models/signature.models';
export interface Group {
id: number;

View File

@ -1,5 +1,4 @@
// CSS is loaded via HTML link tag
// import { initHeader } from '../src/components/header/header'; // Unused import
/*import { initChat } from '../src/pages/chat/chat';*/
import Database from './services/database.service';
import Services from './services/service';
@ -1052,20 +1051,8 @@ async function cleanPage() {
if (container) container.innerHTML = '';
}
// Header functions integrated directly
async function initEssentialFunctions() {
// Import essential functions from header
const headerModule = await import('./components/header/header');
// Make functions globally available
(window as any).importJSON =
headerModule.importJSON || (() => console.warn('importJSON not available'));
(window as any).createBackUp =
headerModule.createBackUp || (() => console.warn('createBackUp not available'));
(window as any).disconnect =
headerModule.disconnect || (() => console.warn('disconnect not available'));
(window as any).unpair = headerModule.unpair || (() => console.warn('unpair not available'));
}
// Essential functions are now handled directly in the application
// No need to import from header component since it was removed
(window as any).navigate = navigate;

View File

@ -47,47 +47,7 @@ export default class ModalService {
document.head.appendChild(newScript).parentNode?.removeChild(newScript);
}
async injectModal(members: any[]) {
const container = document.querySelector('#containerId');
if (container) {
let html = await fetch('/src/components/modal/confirmation-modal.html').then(res =>
res.text()
);
html = html.replace('{{device1}}', await addressToEmoji(members[0]['sp_addresses'][0]));
html = html.replace('{{device2}}', await addressToEmoji(members[0]['sp_addresses'][1]));
container.innerHTML += html;
// Dynamically load the header JS
const script = document.createElement('script');
script.src = '/src/components/modal/confirmation-modal.ts';
script.type = 'module';
document.head.appendChild(script);
}
}
async injectCreationModal(members: any[]) {
const container = document.querySelector('#containerId');
if (container) {
let html = await fetch('/src/components/modal/creation-modal.html').then(res => res.text());
html = html.replace('{{device1}}', await addressToEmoji(members[0]['sp_addresses'][0]));
container.innerHTML += html;
// Dynamically load the header JS
const script = document.createElement('script');
script.src = '/src/components/modal/confirmation-modal.ts';
script.type = 'module';
document.head.appendChild(script);
}
}
// Device 1 wait Device 2
async injectWaitingModal() {
const container = document.querySelector('#containerId');
if (container) {
let html = await fetch('/src/components/modal/waiting-modal.html').then(res => res.text());
container.innerHTML += html;
}
}
// Removed unused modal injection methods
async injectValidationModal(processDiff: any) {
const container = document.querySelector('#containerId');
@ -154,15 +114,8 @@ export default class ModalService {
this.processId = processId;
this.stateId = stateId;
if (members[0].sp_addresses.length === 1) {
await this.injectCreationModal(members);
this.modal = document.getElementById('creation-modal');
console.log('LENGTH:', members[0].sp_addresses.length);
} else {
await this.injectModal(members);
this.modal = document.getElementById('modal');
console.log('LENGTH:', members[0].sp_addresses.length);
}
// Modal injection methods removed - using confirmation modal instead
this.modal = document.getElementById('confirmation-modal');
if (this.modal) this.modal.style.display = 'flex';

View File

@ -23,7 +23,7 @@ import Database from './database.service';
// import { navigate } from '../router'; // Unused import
import { storeData, retrieveData } from './storage.service';
// import { testData } from './storage.service'; // Unused import
import { BackUp } from '~/models/backup.model';
import { BackUp } from '../models/backup.model';
export const U32_MAX = 4294967295;