declare global {
interface Window {
initAccount: () => void;
showContractPopup: (contractId: string) => void;
showPairing: () => void;
showWallet: () => void;
showData: () => void;
addWalletRow: () => void;
confirmWalletRow: () => void;
cancelWalletRow: () => void;
openAvatarPopup: () => void;
closeAvatarPopup: () => void;
editDeviceName: (cell: HTMLTableCellElement) => void;
showNotifications: (processName: string) => void;
closeNotificationPopup: (event: Event) => void;
markAsRead: (processName: string, messageId: number, element: HTMLElement) => void;
exportRecovery: () => void;
confirmDeleteAccount: () => void;
deleteAccount: () => void;
updateNavbarBanner: (bannerUrl: string) => void;
saveBannerToLocalStorage: (bannerUrl: string) => void;
loadSavedBanner: () => void;
cancelAddRow: () => void;
saveName: (cell: HTMLElement, input: HTMLInputElement) => void;
showProcessNotifications: (processName: string) => void;
handleLogout: () => void;
initializeEventListeners: () => void;
showProcess: () => void;
updateNavbarName: (name: string) => void;
updateNavbarLastName: (lastName: string) => void;
showAlert: (title: string, text?: string, icon?: string) => void;
addRow: () => void;
confirmRow: () => void;
cancelRow: () => void;
deleteRow: (button: HTMLButtonElement) => void;
generateRecoveryWords: () => string[];
exportUserData: () => void;
updateActionButtons: () => void;
}
}
import Swal from 'sweetalert2';
import { STORAGE_KEYS, defaultRows, mockProcessRows, mockNotifications, notificationMessages, mockDataRows, mockContracts, ALLOWED_ROLES } from '../../mocks/mock-account/constAccountMock';
import { Row, WalletRow, DataRow, Notification, Contract, NotificationMessage } from '../../mocks/mock-account/interfacesAccountMock';
import { addressToEmoji } from '../../utils/sp-address.utils';
import { getCorrectDOM } from '../../utils/document.utils';
import accountStyle from '../../../public/style/account.css?inline';
let isAddingRow = false;
let currentRow: HTMLTableRowElement | null = null;
let currentMode: keyof typeof STORAGE_KEYS = 'pairing';
class AccountElement extends HTMLElement {
private dom: Node;
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.dom = getCorrectDOM('account-element');
// Ajouter Font Awesome
const fontAwesome = document.createElement('link');
fontAwesome.rel = 'stylesheet';
fontAwesome.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css';
this.shadowRoot!.appendChild(fontAwesome);
const style = document.createElement('style');
style.textContent = accountStyle;
this.shadowRoot!.appendChild(style);
this.shadowRoot!.innerHTML = `
`;
window.showPairing = () => this.showPairing();
window.showWallet = () => this.showWallet();
window.showProcess = () => this.showProcess();
window.showData = () => this.showData();
window.addWalletRow = () => this.addWalletRow();
window.confirmWalletRow = () => this.confirmWalletRow();
window.cancelWalletRow = () => this.cancelWalletRow();
window.editDeviceName = (cell: HTMLTableCellElement) => this.editDeviceName(cell);
window.showProcessNotifications = (processName: string) => this.showProcessNotifications(processName);
window.handleLogout = () => this.handleLogout();
window.confirmDeleteAccount = () => this.confirmDeleteAccount();
window.showContractPopup = (contractId: string) => this.showContractPopup(contractId);
window.addRow = () => this.addRow();
window.deleteRow = (button: HTMLButtonElement) => this.deleteRow(button);
window.confirmRow = () => this.confirmRow();
window.cancelRow = () => this.cancelRow();
window.updateNavbarBanner = (bannerUrl: string) => this.updateNavbarBanner(bannerUrl);
window.saveBannerToLocalStorage = (bannerUrl: string) => this.saveBannerToLocalStorage(bannerUrl);
window.loadSavedBanner = () => this.loadSavedBanner();
window.closeNotificationPopup = (event: Event) => this.closeNotificationPopup(event);
window.markAsRead = (processName: string, messageId: number, element: HTMLElement) => this.markAsRead(processName, messageId, element);
window.exportRecovery = () => this.exportRecovery();
window.generateRecoveryWords = () => this.generateRecoveryWords();
window.exportUserData = () => this.exportUserData();
window.updateActionButtons = () => this.updateActionButtons();
window.openAvatarPopup = () => this.openAvatarPopup();
window.closeAvatarPopup = () => this.closeAvatarPopup();
if (!localStorage.getItem('rows')) {
localStorage.setItem('rows', JSON.stringify(defaultRows));
}
}
connectedCallback() {
this.initializeEventListeners();
this.loadSavedBanner();
this.loadUserInfo();
const savedAvatar = localStorage.getItem('userAvatar');
const savedBanner = localStorage.getItem('userBanner');
const savedName = localStorage.getItem('userName');
const savedLastName = localStorage.getItem('userLastName');
if (savedAvatar) {
const navAvatar = this.shadowRoot?.querySelector('.avatar') as HTMLImageElement;
if (navAvatar) navAvatar.src = savedAvatar;
}
if (savedBanner) {
const navBanner = this.shadowRoot?.querySelector('.banner-image') as HTMLImageElement;
if (navBanner) navBanner.src = savedBanner;
}
if (savedName) {
this.updateNavbarName(savedName);
}
if (savedLastName) {
this.updateNavbarLastName(savedLastName);
}
}
private showAlert(message: string): void {
// Créer la popup si elle n'existe pas
let alertPopup = this.shadowRoot?.querySelector('.alert-popup');
if (!alertPopup) {
alertPopup = document.createElement('div');
alertPopup.className = 'alert-popup';
this.shadowRoot?.appendChild(alertPopup);
}
// Définir le message et afficher la popup
alertPopup.textContent = message;
(alertPopup as HTMLElement).style.display = 'block';
// Cacher la popup après 3 secondes
setTimeout(() => {
(alertPopup as HTMLElement).style.display = 'none';
}, 3000);
}
// Fonctions de gestion des comptes et de l'interface utilisateur
private confirmDeleteAccount(): void {
const modal = document.createElement('div');
modal.className = 'confirm-delete-modal';
modal.innerHTML = `
Delete Account
Are you sure you want to delete your account? This action cannot be undone.
Cancel
Delete
`;
this.shadowRoot?.appendChild(modal);
modal.style.display = 'block';
const cancelBtn = modal.querySelector('.cancel-btn');
const confirmBtn = modal.querySelector('.confirm-btn');
cancelBtn?.addEventListener('click', () => {
modal.remove();
});
confirmBtn?.addEventListener('click', () => {
this.deleteAccount();
modal.remove();
});
}
private deleteAccount(): void {
localStorage.clear();
window.location.href = '/login.html';
}
private updateNavbarBanner(imageUrl: string): void {
const navbarSection = this.shadowRoot?.querySelector('.nav-wrapper .avatar-section');
if (!navbarSection) return;
let bannerImg = navbarSection.querySelector('.banner-image');
if (!bannerImg) {
bannerImg = document.createElement('img');
bannerImg.className = 'banner-image';
navbarSection.insertBefore(bannerImg, navbarSection.firstChild);
}
bannerImg.src = imageUrl;
}
private saveBannerToLocalStorage(dataUrl: string): void {
localStorage.setItem('userBanner', dataUrl);
}
private loadSavedBanner(): void {
const savedBanner = localStorage.getItem('userBanner');
if (savedBanner) {
const bannerImg = this.shadowRoot?.getElementById('popup-banner-img') as HTMLImageElement;
if (bannerImg) {
bannerImg.src = savedBanner;
}
this.updateNavbarBanner(savedBanner);
}
}
private closeNotificationPopup(event: Event): void {
const target = event.target as HTMLElement;
const isOverlay = target.classList.contains('notification-popup-overlay');
const isCloseButton = target.classList.contains('close-popup');
if (!isOverlay && !isCloseButton) return;
const popup = this.shadowRoot?.querySelector('.notification-popup-overlay');
if (popup) popup.remove();
}
private markAsRead(processName: string, messageId: number, element: HTMLElement): void {
const process = mockProcessRows.find(p => p.process === processName);
if (!process) return;
const message = process.notification.messages.find(m => m.id === messageId);
if (!message || message.read) return;
message.read = true;
element.classList.remove('unread');
element.classList.add('read');
const statusIcon = element.querySelector('.notification-status');
if (statusIcon) {
statusIcon.innerHTML = `
`;
}
const notifCount = this.calculateNotifications(process.notification.messages);
const countElement = this.shadowRoot?.querySelector(`.notification-count[data-process="${processName}"]`);
if (countElement) {
countElement.textContent = `${notifCount.unread}/${notifCount.total}`;
const bellContainer = countElement.closest('.notification-container');
const bell = bellContainer?.querySelector('svg'); // Changé de .fa-bell à svg
if (bell && bellContainer && notifCount.unread === 0) {
bellContainer.classList.remove('has-unread');
(bell as SVGElement).style.fill = '#666'; // Utiliser fill au lieu de color pour SVG
}
}
}
// Fonctions de gestion des données et de l'interface
private calculateNotifications(messages: NotificationMessage[]): { unread: number; total: number } {
const total = messages.length;
const unread = messages.filter(msg => !msg.read).length;
return { unread, total };
}
// Fonctions de récupération
private exportRecovery(): void {
Swal.fire({
title: 'Recovery Words Export',
text: '4 words will be displayed. We strongly recommend writing them down on paper before exporting the account. Do you want to continue?',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Confirm',
cancelButtonText: 'Cancel',
confirmButtonColor: '#C89666',
cancelButtonColor: '#6c757d',
// Ajouter des styles personnalisés
customClass: {
container: 'recovery-popup-container',
popup: 'recovery-popup'
}
}).then((result) => {
if (result.isConfirmed) {
const recoveryWords = this.generateRecoveryWords();
localStorage.setItem('recoveryWords', JSON.stringify(recoveryWords));
Swal.fire({
title: 'Your Recovery Words',
html: `
${recoveryWords.map((word, index) => `
${index + 1}.
${word}
`).join('')}
Please write these words down carefully. They will be needed to recover your account.
`,
showCancelButton: false,
confirmButtonText: 'I confirm the export',
confirmButtonColor: '#C89666',
allowOutsideClick: false,
allowEscapeKey: false,
customClass: {
container: 'recovery-popup-container',
popup: 'recovery-popup'
}
}).then((result) => {
if (result.isConfirmed) {
// Stocker l'état du bouton dans le localStorage
localStorage.setItem('recoveryExported', 'true');
const exportRecoveryBtn = this.shadowRoot?.querySelector('.recovery-btn') as HTMLButtonElement;
if (exportRecoveryBtn) {
exportRecoveryBtn.disabled = true;
exportRecoveryBtn.style.opacity = '0.5';
exportRecoveryBtn.style.cursor = 'not-allowed';
}
}
});
}
});
}
private generateRecoveryWords(): string[] {
const wordsList = [
'apple', 'banana', 'orange', 'grape', 'kiwi', 'mango', 'peach', 'plum',
'lemon', 'lime', 'cherry', 'melon', 'pear', 'fig', 'date', 'berry'
];
const recoveryWords: string[] = [];
while (recoveryWords.length < 4) {
const randomWord = wordsList[Math.floor(Math.random() * wordsList.length)];
if (!recoveryWords.includes(randomWord)) {
recoveryWords.push(randomWord);
}
}
return recoveryWords;
}
private exportUserData(): void {
const data: { [key: string]: string | null } = {};
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key) {
const value = localStorage.getItem(key);
data[key] = value;
}
}
const jsonData = JSON.stringify(data, null, 2);
const blob = new Blob([jsonData], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'user_data.json';
this.shadowRoot?.appendChild(a);
a.click();
this.shadowRoot?.removeChild(a);
URL.revokeObjectURL(url);
}
private updateActionButtons(): void {
const buttonContainer = this.shadowRoot?.querySelector('.button-container');
if (!buttonContainer) return;
buttonContainer.innerHTML = `
✓
✗
`;
}
private getConfirmFunction(): string {
switch (currentMode) {
case 'wallet':
return 'window.confirmWalletRow()';
case 'process':
return 'window.confirmProcessRow()';
default:
return 'window.confirmRow()';
}
}
private getCancelFunction(): string {
switch (currentMode) {
case 'wallet':
return 'window.cancelWalletRow()';
case 'process':
return 'window.cancelProcessRow()';
default:
return 'window.cancelRow()';
}
}
// Fonctions de gestion des tableaux
private addRow(): void {
if (isAddingRow) return;
isAddingRow = true;
const table = this.shadowRoot?.querySelector('#pairing-table tbody');
if (!table) return;
currentRow = table.insertRow();
const cells = ['SP Address', 'Device Name', 'SP Emojis'];
cells.forEach((_, index) => {
const cell = currentRow!.insertCell();
const input = document.createElement('input');
input.type = 'text';
input.className = 'edit-input';
// Ajouter un événement pour mettre à jour automatiquement les emojis
if (index === 0) {
input.addEventListener('input', async (e) => {
const addressInput = e.target as HTMLInputElement;
const emojiCell = currentRow!.cells[2];
const emojis = await addressToEmoji(addressInput.value);
if (emojiCell.querySelector('input')) {
(emojiCell.querySelector('input') as HTMLInputElement).value = emojis;
}
});
}
if (index === 2) {
input.readOnly = true;
}
cell.appendChild(input);
});
const deleteCell = currentRow.insertCell();
deleteCell.style.width = '40px';
this.updateActionButtons();
}
// Fonctions de mise à jour de l'interface
private updateTableContent(rows: Row[]): void {
const tbody = this.shadowRoot?.querySelector('#pairing-table tbody');
if (!tbody) return;
tbody.innerHTML = rows.map(row => `
${row.column1}
${row.column2}
${row.column3}
`).join('');
}
private confirmRow(): void {
if (!currentRow) return;
const inputs = currentRow.getElementsByTagName('input');
const values: string[] = Array.from(inputs).map(input => input.value.trim());
// Vérification des champs vides
if (values.some(value => value === '')) {
this.showAlert('Please fill in all fields');
return;
}
// Vérification de la longueur de l'adresse SP
if (values[0].length !== 118) {
this.showAlert('SP Address must be exactly 118 characters long');
return;
}
const newRow: Row = {
column1: values[0],
column2: values[1],
column3: values[2]
};
const storageKey = STORAGE_KEYS[currentMode];
const rows: Row[] = JSON.parse(localStorage.getItem(storageKey) || '[]');
rows.push(newRow);
localStorage.setItem(storageKey, JSON.stringify(rows));
isAddingRow = false;
currentRow = null;
this.resetButtonContainer();
this.updateTableContent(rows);
}
private cancelRow(): void {
if (!currentRow) return;
currentRow.remove();
isAddingRow = false;
currentRow = null;
this.resetButtonContainer();
}
private resetButtonContainer(): void {
const buttonContainer = this.shadowRoot?.querySelector('.button-container');
if (!buttonContainer) return;
buttonContainer.innerHTML = `
Add a line
`;
}
private deleteRow(button: HTMLButtonElement): void {
const row = button.closest('tr');
if (!row) return;
const table = row.closest('tbody');
if (!table) return;
// Vérifier le nombre de lignes restantes
const remainingRows = table.getElementsByTagName('tr').length;
if (remainingRows <= 2) {
this.showAlert('You must keep at least 2 devices paired');
return;
}
// Animation de suppression
row.style.transition = 'opacity 0.3s';
row.style.opacity = '0';
setTimeout(() => {
// Obtenir l'index avant la suppression
const index = Array.from(table.children).indexOf(row);
// Supprimer la ligne du DOM
row.remove();
// Mettre à jour le localStorage
const storageKey = STORAGE_KEYS[currentMode];
const rows = JSON.parse(localStorage.getItem(storageKey) || '[]');
rows.splice(index, 1);
localStorage.setItem(storageKey, JSON.stringify(rows));
}, 300);
}
private editDeviceName(cell: HTMLTableCellElement): void {
if (cell.classList.contains('editing')) return;
const currentValue = cell.textContent || '';
const input = document.createElement('input');
input.type = 'text';
input.value = currentValue;
input.className = 'edit-input';
input.addEventListener('blur', () => this.finishEditing(cell, input));
input.addEventListener('keypress', (e: KeyboardEvent) => {
if (e.key === 'Enter') {
this.finishEditing(cell, input);
}
});
cell.textContent = '';
cell.appendChild(input);
cell.classList.add('editing');
input.focus();
}
private finishEditing(cell: HTMLTableCellElement, input: HTMLInputElement): void {
const newValue = input.value.trim();
if (newValue === '') {
cell.textContent = cell.getAttribute('data-original-value') || '';
cell.classList.remove('editing');
return;
}
const row = cell.closest('tr');
if (!row) return;
const table = row.closest('tbody');
if (!table) return;
const index = Array.from(table.children).indexOf(row);
const storageKey = STORAGE_KEYS[currentMode];
const rows: Row[] = JSON.parse(localStorage.getItem(storageKey) || '[]');
if (rows[index]) {
rows[index].column2 = newValue;
localStorage.setItem(storageKey, JSON.stringify(rows));
}
cell.textContent = newValue;
cell.classList.remove('editing');
}
// Fonction pour gérer le téléchargement de l'avatar
private handleAvatarUpload(event: Event): void {
const input = event.target as HTMLInputElement;
const file = input.files?.[0];
if (file) {
const reader = new FileReader();
reader.onload = (e: ProgressEvent) => {
const result = e.target?.result as string;
const popupAvatar = this.shadowRoot?.getElementById('popup-avatar-img') as HTMLImageElement;
const navAvatar = this.shadowRoot?.querySelector('.nav-wrapper .avatar') as HTMLImageElement;
if (popupAvatar) popupAvatar.src = result;
if (navAvatar) navAvatar.src = result;
localStorage.setItem('userAvatar', result);
};
reader.readAsDataURL(file);
}
}
private showProcess(): void {
//console.log("showProcess called");
currentMode = 'process';
this.hideAllContent();
const headerTitle = this.shadowRoot?.getElementById('header-title');
if (headerTitle) headerTitle.textContent = 'Process';
const processContent = this.shadowRoot?.getElementById('process-content');
if (processContent) {
processContent.style.display = 'block';
processContent.innerHTML = `
Process Name
Role
Notifications
`;
this.updateProcessTableContent(mockProcessRows);
}
}
// Fonction utilitaire pour mettre à jour le contenu du tableau Process
private updateProcessTableContent(rows: any[]): void {
const tbody = this.shadowRoot?.querySelector('#process-table tbody');
if (!tbody) return;
tbody.innerHTML = rows.map(row => `
${row.process}
${row.role}
${row.notification?.messages?.filter((m: any) => !m.read).length || 0}/${row.notification?.messages?.length || 0}
`).join('');
}
private showProcessNotifications(processName: string): void {
const process = mockProcessRows.find(p => p.process === processName);
if (!process) return;
const modal = document.createElement('div');
modal.className = 'notifications-modal';
let notificationsList = process.notification.messages.map(msg => `
${msg.message}
${msg.date}
`).join('');
if (process.notification.messages.length === 0) {
notificationsList = 'No notifications
';
}
modal.innerHTML = `
${processName} Notifications
${notificationsList}
x
`;
this.shadowRoot?.appendChild(modal);
// Mettre à jour le compteur de notifications
const countElement = this.shadowRoot?.querySelector(`.notification-count[data-process="${processName}"]`);
if (countElement) {
const notifCount = this.calculateNotifications(process.notification.messages);
countElement.textContent = `${notifCount.unread}/${notifCount.total}`;
}
const closeButton = modal.querySelector('.close-notifications');
closeButton?.addEventListener('click', () => {
modal.remove();
this.showProcess(); // Rafraîchir l'affichage pour mettre à jour les compteurs
});
}
private handleLogout(): void {
localStorage.clear();
window.location.href = '../login/login.html';
}
// Fonctions de gestion des contrats
private showContractPopup(contractId: string) {
// Empêcher la navigation par défaut
event?.preventDefault();
// Check if the contract exists in mockContracts
const contract = mockContracts[contractId as keyof typeof mockContracts];
if (!contract) {
console.error('Contract not found:', contractId);
return;
}
// Créer la popup
const popup = document.createElement('div');
popup.className = 'contract-popup-overlay';
popup.innerHTML = `
`;
// Ajouter la popup au body
this.shadowRoot?.appendChild(popup);
// Gérer la fermeture
const closeBtn = popup.querySelector('.close-contract-popup');
const closePopup = () => popup.remove();
closeBtn?.addEventListener('click', closePopup);
popup.addEventListener('click', (e) => {
if (e.target === popup) closePopup();
});
}
// Ajouter à l'objet window
// Fonction utilitaire pour cacher tous les contenus
private hideAllContent(): void {
const contents = ['pairing-content', 'wallet-content', 'process-content', 'data-content'];
contents.forEach(id => {
const element = this.shadowRoot?.getElementById(id);
if (element) {
element.style.display = 'none';
}
});
}
// Fonctions d'affichage des sections
private showPairing(): void {
isAddingRow = false;
currentRow = null;
currentMode = 'pairing';
// Cacher tous les contenus
this.hideAllContent();
// Mettre à jour le titre
const headerElement = this.shadowRoot?.getElementById('parameter-header');
if (headerElement) {
headerElement.textContent = 'Pairing';
}
// Afficher le contenu de pairing
const pairingContent = this.shadowRoot?.getElementById('pairing-content');
if (pairingContent) {
pairingContent.style.display = 'block';
pairingContent.innerHTML = `
SP Address
Device Name
SP Emojis
Add a line
`;
// Mettre à jour le contenu du tableau
const rows = JSON.parse(localStorage.getItem(STORAGE_KEYS.pairing) || '[]');
this.updateTableContent(rows);
}
}
private showWallet(): void {
isAddingRow = false;
currentRow = null;
currentMode = 'wallet';
this.hideAllContent();
// Mettre à jour le titre
const headerTitle = this.shadowRoot?.getElementById('header-title');
if (headerTitle) headerTitle.textContent = 'Wallet';
const walletContent = this.shadowRoot?.getElementById('wallet-content');
if (!walletContent) return;
walletContent.style.display = 'block';
walletContent.innerHTML = `
`;
const rows = JSON.parse(localStorage.getItem(STORAGE_KEYS.wallet) || '[]');
this.updateWalletTableContent(rows);
}
private updateWalletTableContent(rows: WalletRow[]): void {
const tbody = this.shadowRoot?.querySelector('#wallet-table tbody');
if (!tbody) return;
tbody.innerHTML = rows.map(row => `
${row.column1}
${row.column2}
${row.column3}
`).join('');
}
private showData(): void {
//console.log("showData called");
currentMode = 'data';
this.hideAllContent();
const headerTitle = this.shadowRoot?.getElementById('header-title');
if (headerTitle) headerTitle.textContent = 'Data';
const dataContent = this.shadowRoot?.getElementById('data-content');
if (dataContent) {
dataContent.style.display = 'block';
dataContent.innerHTML = `
Name
Visibility
Role
Duration
Legal
Contract
`;
const rows = mockDataRows || JSON.parse(localStorage.getItem(STORAGE_KEYS.data) || '[]');
this.updateDataTableContent(rows);
}
}
// Fonctions de gestion du wallet
private addWalletRow(): void {
if (isAddingRow) return;
isAddingRow = true;
const table = this.shadowRoot?.getElementById('wallet-table')?.getElementsByTagName('tbody')[0];
if (!table) return;
currentRow = table.insertRow();
const placeholders = ['Label', 'Wallet', 'Type'];
placeholders.forEach(placeholder => {
const cell = currentRow!.insertCell();
const input = document.createElement('input');
input.type = 'text';
input.placeholder = placeholder;
input.className = 'edit-input';
cell.appendChild(input);
});
// Remplacer le bouton "Add a line" par les boutons de confirmation/annulation
const buttonContainer = this.shadowRoot?.querySelector('#wallet-content .button-container');
if (!buttonContainer) return;
buttonContainer.innerHTML = `
✓
✗
`;
this.updateActionButtons();
}
private confirmWalletRow(): void {
if (!currentRow) return;
const inputs = Array.from(currentRow.getElementsByTagName('input'));
const allFieldsFilled = inputs.every(input => input.value.trim() !== '');
if (allFieldsFilled) {
const newRow: WalletRow = {
column1: inputs[0].value.trim(),
column2: inputs[1].value.trim(),
column3: inputs[2].value.trim()
};
const rows = JSON.parse(localStorage.getItem(STORAGE_KEYS.wallet) || '[]');
rows.push(newRow);
localStorage.setItem(STORAGE_KEYS.wallet, JSON.stringify(rows));
isAddingRow = false;
currentRow = null;
this.showWallet();
} else {
this.showAlert('Please complete all fields before confirming.');
}
}
private cancelWalletRow(): void {
if (!currentRow) return;
currentRow.remove();
isAddingRow = false;
currentRow = null;
// Réinitialiser le conteneur de boutons avec le bouton "Add a line"
const buttonContainer = this.shadowRoot?.querySelector('#wallet-content .button-container');
if (!buttonContainer) return;
buttonContainer.innerHTML = `
Add a line
`;
}
private updateDataTableContent(rows: DataRow[]): void {
const tbody = this.shadowRoot?.querySelector('#data-table tbody');
if (!tbody) return;
tbody.innerHTML = rows.map(row => `
${row.column1}
${row.column2}
${row.column3}
${row.column4}
${row.column5}
${row.column6}
`).join('');
}
// Fonctions de gestion de l'avatar et de la bannière
private openAvatarPopup(): void {
const popup = this.shadowRoot?.getElementById('avatar-popup');
if (!popup) return;
// Récuprer les valeurs stockées
const savedName = localStorage.getItem('userName');
const savedLastName = localStorage.getItem('userLastName');
const savedAvatar = localStorage.getItem('userAvatar') || 'https://via.placeholder.com/150';
const savedBanner = localStorage.getItem('userBanner') || 'https://via.placeholder.com/800x200';
const savedAddress = localStorage.getItem('userAddress') || '🏠 🌍 🗽🎊😩-🎊😑😩';
popup.innerHTML = `
`;
popup.style.display = 'block';
this.setupEventListeners(popup);
// Ajouter le gestionnaire d'événements pour la bannière
const bannerImg = popup.querySelector('#popup-banner-img');
const bannerInput = popup.querySelector('#banner-upload') as HTMLInputElement;
if (bannerImg && bannerInput) {
bannerImg.addEventListener('click', () => {
bannerInput.click();
});
}
const recoveryExported = localStorage.getItem('recoveryExported') === 'true';
if (recoveryExported) {
const exportRecoveryBtn = popup.querySelector('.recovery-btn') as HTMLButtonElement;
if (exportRecoveryBtn) {
exportRecoveryBtn.disabled = true;
exportRecoveryBtn.style.opacity = '0.5';
exportRecoveryBtn.style.cursor = 'not-allowed';
}
}
}
private setupEventListeners(popup: HTMLElement): void {
// Gestionnaire pour la fermeture
const closeBtn = popup.querySelector('.close-popup');
if (closeBtn) {
closeBtn.addEventListener('click', () => {
popup.style.display = 'none';
});
}
// Gestionnaire pour l'upload d'avatar
const avatarUpload = popup.querySelector('#avatar-upload') as HTMLInputElement;
if (avatarUpload) {
avatarUpload.addEventListener('change', (e: Event) => {
const file = (e.target as HTMLInputElement).files?.[0];
if (file) {
const reader = new FileReader();
reader.onload = (e: ProgressEvent) => {
const result = e.target?.result as string;
// Mise à jour de l'avatar dans la preview et le popup
const popupAvatar = this.shadowRoot?.getElementById('popup-avatar-img') as HTMLImageElement;
const previewAvatar = this.shadowRoot?.querySelector('.preview-avatar') as HTMLImageElement;
if (popupAvatar) popupAvatar.src = result;
if (previewAvatar) previewAvatar.src = result;
localStorage.setItem('userAvatar', result);
};
reader.readAsDataURL(file);
}
});
}
// Gestionnaire pour l'upload de bannière
const bannerUpload = popup.querySelector('#banner-upload') as HTMLInputElement;
if (bannerUpload) {
bannerUpload.addEventListener('change', (e: Event) => {
const file = (e.target as HTMLInputElement).files?.[0];
if (file) {
const reader = new FileReader();
reader.onload = (e: ProgressEvent) => {
const result = e.target?.result as string;
// Mise à jour de la bannière dans la preview et le popup
const popupBanner = this.shadowRoot?.getElementById('popup-banner-img') as HTMLImageElement;
const previewBanner = this.shadowRoot?.querySelector('.preview-banner-img') as HTMLImageElement;
if (popupBanner) popupBanner.src = result;
if (previewBanner) previewBanner.src = result;
localStorage.setItem('userBanner', result);
};
reader.readAsDataURL(file);
}
});
}
// Gestionnaires pour les champs de texte
const nameInput = popup.querySelector('#userName') as HTMLInputElement;
const lastNameInput = popup.querySelector('#userLastName') as HTMLInputElement;
if (nameInput) {
nameInput.addEventListener('input', () => {
const newName = nameInput.value;
localStorage.setItem('userName', newName);
// Mise à jour du nom dans la preview
const previewName = this.shadowRoot?.querySelector('.preview-name');
if (previewName) previewName.textContent = newName;
});
}
if (lastNameInput) {
lastNameInput.addEventListener('input', () => {
const newLastName = lastNameInput.value;
localStorage.setItem('userLastName', newLastName);
// Mise à jour du nom de famille dans la preview
const previewLastName = this.shadowRoot?.querySelector('.preview-lastname');
if (previewLastName) previewLastName.textContent = newLastName;
});
}
}
private closeAvatarPopup(): void {
const popup = this.shadowRoot?.querySelector('.avatar-popup');
if (popup) popup.remove();
}
private loadAvatar(): void {
const savedAvatar = localStorage.getItem('userAvatar');
if (savedAvatar) {
const avatarImg = this.shadowRoot?.querySelector('.avatar') as HTMLImageElement;
if (avatarImg) {
avatarImg.src = savedAvatar;
}
}
}
private loadUserInfo(): void {
const savedName = localStorage.getItem('userName');
const savedLastName = localStorage.getItem('userLastName');
const savedAvatar = localStorage.getItem('userAvatar');
const savedBanner = localStorage.getItem('userBanner');
// Mise à jour du nom dans la preview
if (savedName) {
const previewName = this.shadowRoot?.querySelector('.preview-name');
if (previewName) {
previewName.textContent = savedName;
}
}
// Mise à jour du nom de famille dans la preview
if (savedLastName) {
const previewLastName = this.shadowRoot?.querySelector('.preview-lastname');
if (previewLastName) {
previewLastName.textContent = savedLastName;
}
}
// Mise à jour de l'avatar dans la preview
if (savedAvatar) {
const previewAvatar = this.shadowRoot?.querySelector('.preview-avatar') as HTMLImageElement;
if (previewAvatar) {
previewAvatar.src = savedAvatar;
}
}
// Mise à jour de la bannière dans la preview
if (savedBanner) {
const previewBanner = this.shadowRoot?.querySelector('.preview-banner-img') as HTMLImageElement;
if (previewBanner) {
previewBanner.src = savedBanner;
}
}
}
private updateNavbarName(name: string): void {
const nameElement = this.shadowRoot?.querySelector('.nav-wrapper .user-name');
if (nameElement) {
nameElement.textContent = name;
}
}
private updateNavbarLastName(lastName: string): void {
const lastNameElement = this.shadowRoot?.querySelector('.nav-wrapper .user-lastname');
if (lastNameElement) {
lastNameElement.textContent = lastName;
}
}
private updateProfilePreview(data: {
avatar?: string,
banner?: string,
name?: string,
lastName?: string
}): void {
if (data.avatar) {
const previewAvatar = this.shadowRoot?.querySelector('.preview-avatar') as HTMLImageElement;
if (previewAvatar) previewAvatar.src = data.avatar;
}
if (data.banner) {
const previewBanner = this.shadowRoot?.querySelector('.preview-banner-img') as HTMLImageElement;
if (previewBanner) previewBanner.src = data.banner;
}
if (data.name) {
const previewName = this.shadowRoot?.querySelector('.preview-name');
if (previewName) previewName.textContent = data.name;
}
if (data.lastName) {
const previewLastName = this.shadowRoot?.querySelector('.preview-lastname');
if (previewLastName) previewLastName.textContent = data.lastName;
}
}
private initializeEventListeners() {
this.shadowRoot?.addEventListener('DOMContentLoaded', () => {
this.showPairing();
});
const editableFields = this.shadowRoot?.querySelectorAll('.editable');
if (editableFields) {
editableFields.forEach(field => {
field.addEventListener('click', () => {
if (!field.classList.contains('editing')) {
const currentValue = field.textContent || '';
const input = document.createElement('input');
input.type = 'text';
input.value = currentValue;
input.className = 'edit-input';
field.textContent = '';
field.appendChild(input);
field.classList.add('editing');
input.focus();
}
});
});
}
const avatarInput = this.shadowRoot?.getElementById('avatar-upload') as HTMLInputElement;
if (avatarInput) {
avatarInput.addEventListener('change', this.handleAvatarUpload.bind(this));
}
}
}
customElements.define('account-element', AccountElement);
export { AccountElement };