1894 lines
61 KiB
TypeScript
Executable File
1894 lines
61 KiB
TypeScript
Executable File
import Swal from 'sweetalert2';
|
||
|
||
|
||
//console.log("Account script loaded");
|
||
|
||
let isAddingRow = false;
|
||
let currentRow: HTMLTableRowElement | null = null;
|
||
let currentMode: keyof typeof STORAGE_KEYS = 'pairing';
|
||
|
||
interface Row {
|
||
column1: string;
|
||
column2: string;
|
||
column3: string;
|
||
}
|
||
|
||
// Types supplémentaires nécessaires
|
||
interface Contract {
|
||
title: string;
|
||
date: string;
|
||
parties: string[];
|
||
terms: string[];
|
||
content: string;
|
||
}
|
||
|
||
interface WalletRow {
|
||
column1: string; // Label
|
||
column2: string; // Wallet
|
||
column3: string; // Type
|
||
}
|
||
|
||
interface DataRow {
|
||
column1: string; // Name
|
||
column2: string; // Visibility
|
||
column3: string; // Role
|
||
column4: string; // Duration
|
||
column5: string; // Legal
|
||
column6: string; // Contract
|
||
processName: string;
|
||
zone: string;
|
||
}
|
||
|
||
const ALLOWED_ROLES = ['User', 'Member', 'Peer', 'Payment', 'Deposit', 'Artefact', 'Resolve', 'Backup'];
|
||
|
||
const STORAGE_KEYS = {
|
||
pairing: 'pairingRows',
|
||
wallet: 'walletRows',
|
||
process: 'processRows',
|
||
data: 'dataRows'
|
||
};
|
||
|
||
// Initialiser le stockage des lignes par défaut dans le localStorage
|
||
const defaultRows = [
|
||
{
|
||
column1: "sprt1qqwtvg5q5vcz0reqvmld98u7va3av6gakwe9yxw9yhnpj5djcunn4squ68tuzn8dz78dg4adfv0dekx8hg9sy0t6s9k5em7rffgxmrsfpyy7gtyrz",
|
||
column2: "🎊😑🎄😩",
|
||
column3: "Laptop"
|
||
},
|
||
{
|
||
column1: "sprt1qqwtvg5q5vcz0reqvmld98u7va3av6gakwe9yxw9yhnpj5djcunn4squ68tuzn8dz78dg4adfv0dekx8hg9sy0t6s9k5em7rffgxmrsfpyy7gtyrx",
|
||
column2: "🎏🎕😧🌥",
|
||
column3: "Phone" }
|
||
];
|
||
|
||
// Vérifier si les lignes sont déjà dans le localStorage
|
||
if (!localStorage.getItem('rows')) {
|
||
localStorage.setItem('rows', JSON.stringify(defaultRows));
|
||
}
|
||
|
||
// Add this interface
|
||
interface Notification {
|
||
message: string;
|
||
timestamp: string;
|
||
isRead: boolean;
|
||
}
|
||
|
||
// Update the declaration
|
||
const mockNotifications: { [key: string]: Notification[] } = {};
|
||
|
||
const notificationMessages = [
|
||
"CPU usage high",
|
||
"Memory threshold reached",
|
||
"New update available",
|
||
"Backup completed",
|
||
"Security check required",
|
||
"Performance optimization needed",
|
||
"System alert",
|
||
"Network connectivity issue",
|
||
"Storage space low",
|
||
"Process checkpoint reached"
|
||
];
|
||
|
||
const mockDataRows = [
|
||
{
|
||
column1: "User Project",
|
||
column2: "private",
|
||
column3: "User",
|
||
column4: "6 months",
|
||
column5: "NDA signed",
|
||
column6: "Contract #123",
|
||
processName: "User Process",
|
||
zone: "A"
|
||
},
|
||
{
|
||
column1: "Process Project",
|
||
column2: "private",
|
||
column3: "Process",
|
||
column4: "1 year",
|
||
column5: "Terms accepted",
|
||
column6: "Contract #456",
|
||
processName: "Process Management",
|
||
zone: "B"
|
||
},
|
||
{
|
||
column1: "Member Project",
|
||
column2: "private",
|
||
column3: "Member",
|
||
column4: "3 months",
|
||
column5: "GDPR compliant",
|
||
column6: "Contract #789",
|
||
processName: "Member Process",
|
||
zone: "C"
|
||
},
|
||
{
|
||
column1: "Peer Project",
|
||
column2: "public",
|
||
column3: "Peer",
|
||
column4: "2 years",
|
||
column5: "IP rights",
|
||
column6: "Contract #101",
|
||
processName: "Peer Process",
|
||
zone: "D"
|
||
},
|
||
{
|
||
column1: "Payment Project",
|
||
column2: "confidential",
|
||
column3: "Payment",
|
||
column4: "1 year",
|
||
column5: "NDA signed",
|
||
column6: "Contract #102",
|
||
processName: "Payment Process",
|
||
zone: "E"
|
||
},
|
||
{
|
||
column1: "Deposit Project",
|
||
column2: "private",
|
||
column3: "Deposit",
|
||
column4: "6 months",
|
||
column5: "Terms accepted",
|
||
column6: "Contract #103",
|
||
processName: "Deposit Process",
|
||
zone: "F"
|
||
},
|
||
{
|
||
column1: "Artefact Project",
|
||
column2: "public",
|
||
column3: "Artefact",
|
||
column4: "1 year",
|
||
column5: "GDPR compliant",
|
||
column6: "Contract #104",
|
||
processName: "Artefact Process",
|
||
zone: "G"
|
||
},
|
||
{
|
||
column1: "Resolve Project",
|
||
column2: "private",
|
||
column3: "Resolve",
|
||
column4: "2 years",
|
||
column5: "IP rights",
|
||
column6: "Contract #105",
|
||
processName: "Resolve Process",
|
||
zone: "H"
|
||
},
|
||
{
|
||
column1: "Backup Project",
|
||
column2: "public",
|
||
column3: "Backup",
|
||
column4: "1 year",
|
||
column5: "NDA signed",
|
||
column6: "Contract #106",
|
||
processName: "Backup Process",
|
||
zone: "I"
|
||
}
|
||
];
|
||
|
||
const mockProcessRows = [
|
||
{
|
||
process: "User Project",
|
||
role: "User",
|
||
notification: {
|
||
messages: [
|
||
{ id: 1, read: false, date: "2024-03-10", message: "New user joined the project" },
|
||
{ id: 2, read: false, date: "2024-03-09", message: "Project milestone reached" },
|
||
{ id: 3, read: false, date: "2024-03-08", message: "Security update required" },
|
||
{ id: 4, read: true, date: "2024-03-07", message: "Weekly report available" },
|
||
{ id: 5, read: true, date: "2024-03-06", message: "Team meeting scheduled" }
|
||
]
|
||
}
|
||
},
|
||
{
|
||
process: "Member Project",
|
||
role: "Member",
|
||
notification: {
|
||
messages: [
|
||
{ id: 6, read: true, date: "2024-03-10", message: "Member access granted" },
|
||
{ id: 7, read: true, date: "2024-03-09", message: "Documentation updated" },
|
||
{ id: 8, read: true, date: "2024-03-08", message: "Project status: on track" }
|
||
]
|
||
}
|
||
},
|
||
{
|
||
process: "Peer Project",
|
||
role: "Peer",
|
||
notification: {
|
||
unread: 2,
|
||
total: 4,
|
||
messages: [
|
||
{ id: 9, read: false, date: "2024-03-10", message: "New peer project added" },
|
||
{ id: 10, read: false, date: "2024-03-09", message: "Project milestone reached" },
|
||
{ id: 11, read: false, date: "2024-03-08", message: "Security update required" },
|
||
{ id: 12, read: true, date: "2024-03-07", message: "Weekly report available" },
|
||
{ id: 13, read: true, date: "2024-03-06", message: "Team meeting scheduled" }
|
||
]
|
||
}
|
||
},
|
||
{
|
||
process: "Deposit Project",
|
||
role: "Deposit",
|
||
notification: {
|
||
unread: 1,
|
||
total: 10,
|
||
messages: [
|
||
{ id: 14, read: false, date: "2024-03-10", message: "Deposit milestone reached" },
|
||
{ id: 15, read: false, date: "2024-03-09", message: "Security update required" },
|
||
{ id: 16, read: false, date: "2024-03-08", message: "Weekly report available" },
|
||
{ id: 17, read: true, date: "2024-03-07", message: "Team meeting scheduled" },
|
||
{ id: 18, read: true, date: "2024-03-06", message: "Project status: on track" }
|
||
]
|
||
}
|
||
},
|
||
{
|
||
process: "Artefact Project",
|
||
role: "Artefact",
|
||
notification: {
|
||
unread: 0,
|
||
total: 3,
|
||
messages: [
|
||
{ id: 19, read: false, date: "2024-03-10", message: "New artefact added" },
|
||
{ id: 20, read: false, date: "2024-03-09", message: "Security update required" },
|
||
{ id: 21, read: false, date: "2024-03-08", message: "Weekly report available" },
|
||
{ id: 22, read: true, date: "2024-03-07", message: "Team meeting scheduled" },
|
||
{ id: 23, read: true, date: "2024-03-06", message: "Project status: on track" }
|
||
]
|
||
}
|
||
},
|
||
{
|
||
process: "Resolve Project",
|
||
role: "Resolve",
|
||
notification: {
|
||
unread: 5,
|
||
total: 12,
|
||
messages: [
|
||
{ id: 24, read: false, date: "2024-03-10", message: "New issue reported" },
|
||
{ id: 25, read: false, date: "2024-03-09", message: "Security update required" },
|
||
{ id: 26, read: false, date: "2024-03-08", message: "Weekly report available" },
|
||
{ id: 27, read: true, date: "2024-03-07", message: "Team meeting scheduled" },
|
||
{ id: 28, read: true, date: "2024-03-06", message: "Project status: on track" }
|
||
]
|
||
}
|
||
}
|
||
];
|
||
|
||
|
||
const mockContracts = {
|
||
'Contract #123': {
|
||
title: "User Project Agreement",
|
||
date: "2024-01-15",
|
||
parties: ["Company XYZ", "User Team"],
|
||
terms: [
|
||
"Data Protection",
|
||
"User Privacy",
|
||
"Access Rights",
|
||
"Service Level Agreement"
|
||
],
|
||
content: "This agreement establishes the terms and conditions for user data management and privacy protection..."
|
||
},
|
||
'Contract #456': {
|
||
title: "Process Management Contract",
|
||
date: "2024-02-01",
|
||
parties: ["Company XYZ", "Process Team"],
|
||
terms: [
|
||
"Process Workflow",
|
||
"Quality Standards",
|
||
"Performance Metrics",
|
||
"Monitoring Procedures"
|
||
],
|
||
content: "This contract defines the process management standards and operational procedures..."
|
||
}
|
||
};
|
||
|
||
// Fonctions de gestion des comptes et de l'interface utilisateur
|
||
function confirmDeleteAccount(): void {
|
||
const modal = document.createElement('div');
|
||
modal.className = 'confirm-delete-modal';
|
||
modal.innerHTML = `
|
||
<h3>Delete Account</h3>
|
||
<p>Are you sure you want to delete your account? This action cannot be undone.</p>
|
||
<div class="confirm-delete-buttons">
|
||
<button class="cancel-btn">Cancel</button>
|
||
<button class="confirm-btn">Delete</button>
|
||
</div>
|
||
`;
|
||
|
||
document.body.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', () => {
|
||
deleteAccount();
|
||
modal.remove();
|
||
});
|
||
}
|
||
|
||
function deleteAccount(): void {
|
||
localStorage.clear();
|
||
window.location.href = '/login.html';
|
||
}
|
||
|
||
function updateNavbarBanner(imageUrl: string): void {
|
||
const navbarSection = document.querySelector('.nav-wrapper .avatar-section');
|
||
if (!navbarSection) return;
|
||
|
||
let bannerImg = navbarSection.querySelector<HTMLImageElement>('.banner-image');
|
||
|
||
if (!bannerImg) {
|
||
bannerImg = document.createElement('img');
|
||
bannerImg.className = 'banner-image';
|
||
navbarSection.insertBefore(bannerImg, navbarSection.firstChild);
|
||
}
|
||
|
||
bannerImg.src = imageUrl;
|
||
}
|
||
|
||
function saveBannerToLocalStorage(dataUrl: string): void {
|
||
localStorage.setItem('userBanner', dataUrl);
|
||
}
|
||
|
||
function loadSavedBanner(): void {
|
||
const savedBanner = localStorage.getItem('userBanner');
|
||
if (savedBanner) {
|
||
const bannerImg = document.getElementById('popup-banner-img') as HTMLImageElement;
|
||
if (bannerImg) {
|
||
bannerImg.src = savedBanner;
|
||
}
|
||
updateNavbarBanner(savedBanner);
|
||
}
|
||
}
|
||
|
||
|
||
function 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 = document.querySelector('.notification-popup-overlay');
|
||
if (popup) popup.remove();
|
||
}
|
||
|
||
function 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 i');
|
||
if (statusIcon) {
|
||
statusIcon.classList.remove('fa-circle');
|
||
statusIcon.classList.add('fa-check');
|
||
}
|
||
|
||
const notifCount = calculateNotifications(process.notification.messages);
|
||
const countElement = document.querySelector(`.notification-count[data-process="${processName}"]`);
|
||
if (countElement) {
|
||
countElement.textContent = `${notifCount.unread}/${notifCount.total}`;
|
||
|
||
const bellContainer = countElement.closest('.notification-container');
|
||
const bell = bellContainer?.querySelector('.fa-bell');
|
||
if (bell && bellContainer && notifCount.unread === 0) {
|
||
bellContainer.classList.remove('has-unread');
|
||
(bell as HTMLElement).style.color = '#666';
|
||
}
|
||
}
|
||
}
|
||
|
||
// Fonctions de gestion des données et de l'interface
|
||
interface NotificationMessage {
|
||
id: number;
|
||
read: boolean;
|
||
date: string;
|
||
message: string;
|
||
}
|
||
|
||
function 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
|
||
function 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'
|
||
}).then((result) => {
|
||
if (result.isConfirmed) {
|
||
const recoveryWords = generateRecoveryWords();
|
||
localStorage.setItem('recoveryWords', JSON.stringify(recoveryWords));
|
||
|
||
Swal.fire({
|
||
title: 'Your Recovery Words',
|
||
html: `
|
||
<div class="recovery-words-container">
|
||
${recoveryWords.map((word, index) => `
|
||
<div class="recovery-word">
|
||
<span class="word-number">${index + 1}.</span>
|
||
<span class="word">${word}</span>
|
||
</div>
|
||
`).join('')}
|
||
</div>
|
||
<div class="recovery-warning">
|
||
Please write these words down carefully. They will be needed to recover your account.
|
||
</div>
|
||
`,
|
||
showCancelButton: false,
|
||
confirmButtonText: 'I confirm the export',
|
||
confirmButtonColor: '#C89666',
|
||
allowOutsideClick: false,
|
||
allowEscapeKey: false
|
||
}).then((result) => {
|
||
if (result.isConfirmed) {
|
||
// Stocker l'état du bouton dans le localStorage
|
||
localStorage.setItem('recoveryExported', 'true');
|
||
|
||
const exportRecoveryBtn = document.querySelector('.recovery-btn') as HTMLButtonElement;
|
||
if (exportRecoveryBtn) {
|
||
exportRecoveryBtn.disabled = true;
|
||
exportRecoveryBtn.style.opacity = '0.5';
|
||
exportRecoveryBtn.style.cursor = 'not-allowed';
|
||
}
|
||
}
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
const wordsList: string[] = [
|
||
"apple", "banana", "carrot", "diamond", "elephant", "forest", "guitar", "hammer",
|
||
"island", "jacket", "kettle", "lemon", "marble", "needle", "orange", "pencil",
|
||
"quartz", "rabbit", "sunset", "turtle", "umbrella", "violet", "wallet", "yellow"
|
||
];
|
||
|
||
function generateRecoveryWords(): string[] {
|
||
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;
|
||
}
|
||
|
||
function 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';
|
||
document.body.appendChild(a);
|
||
a.click();
|
||
document.body.removeChild(a);
|
||
URL.revokeObjectURL(url);
|
||
}
|
||
|
||
function updateActionButtons(): void {
|
||
const buttonContainer = document.querySelector('.button-container');
|
||
if (!buttonContainer) return;
|
||
|
||
buttonContainer.innerHTML = `
|
||
<div class="action-buttons-wrapper">
|
||
<button onclick="${getConfirmFunction()}" class="action-button confirm-button">✓</button>
|
||
<button onclick="${getCancelFunction()}" class="action-button cancel-button">✗</button>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
function getConfirmFunction(): string {
|
||
switch (currentMode) {
|
||
case 'wallet':
|
||
return 'window.confirmWalletRow()';
|
||
case 'process':
|
||
return 'window.confirmProcessRow()';
|
||
default:
|
||
return 'window.confirmRow()';
|
||
}
|
||
}
|
||
|
||
function getCancelFunction(): string {
|
||
switch (currentMode) {
|
||
case 'wallet':
|
||
return 'window.cancelWalletRow()';
|
||
case 'process':
|
||
return 'window.cancelProcessRow()';
|
||
default:
|
||
return 'window.cancelRow()';
|
||
}
|
||
}
|
||
|
||
// Fonctions de gestion des tableaux
|
||
function addRow(): void {
|
||
if (isAddingRow) return;
|
||
|
||
isAddingRow = true;
|
||
const table = document.querySelector<HTMLTableElement>('#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) { // SP Address input
|
||
input.addEventListener('input', (e) => {
|
||
const addressInput = e.target as HTMLInputElement;
|
||
const emojiCell = currentRow!.cells[2]; // Changé à 2 pour la troisième colonne
|
||
const emojis = addressToEmoji(addressInput.value);
|
||
if (emojiCell.querySelector('input')) {
|
||
(emojiCell.querySelector('input') as HTMLInputElement).value = emojis;
|
||
}
|
||
});
|
||
}
|
||
|
||
// Désactiver l'input des emojis car il est automatique
|
||
if (index === 2) { // SP Emojis input (troisième colonne)
|
||
input.readOnly = true;
|
||
}
|
||
|
||
cell.appendChild(input);
|
||
});
|
||
|
||
const deleteCell = currentRow.insertCell();
|
||
deleteCell.style.width = '40px';
|
||
|
||
updateActionButtons();
|
||
}
|
||
|
||
|
||
|
||
function 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 === '')) {
|
||
showAlert('Please fill in all fields');
|
||
return;
|
||
}
|
||
|
||
// Vérification de la longueur de l'adresse SP
|
||
if (values[0].length !== 118) {
|
||
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;
|
||
|
||
resetButtonContainer();
|
||
updateTableContent(rows);
|
||
}
|
||
|
||
function cancelRow(): void {
|
||
if (!currentRow) return;
|
||
|
||
currentRow.remove();
|
||
isAddingRow = false;
|
||
currentRow = null;
|
||
|
||
resetButtonContainer();
|
||
}
|
||
|
||
function resetButtonContainer(): void {
|
||
const buttonContainer = document.querySelector('.button-container');
|
||
if (!buttonContainer) return;
|
||
|
||
buttonContainer.innerHTML = `
|
||
<button class="add-row-button button-style" onclick="addRow()">Add a line</button>
|
||
`;
|
||
}
|
||
|
||
function 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) {
|
||
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);
|
||
}
|
||
|
||
function 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', () => finishEditing(cell, input));
|
||
input.addEventListener('keypress', (e: KeyboardEvent) => {
|
||
if (e.key === 'Enter') {
|
||
finishEditing(cell, input);
|
||
}
|
||
});
|
||
|
||
cell.textContent = '';
|
||
cell.appendChild(input);
|
||
cell.classList.add('editing');
|
||
input.focus();
|
||
}
|
||
|
||
function 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].column3 = newValue;
|
||
localStorage.setItem(storageKey, JSON.stringify(rows));
|
||
}
|
||
|
||
cell.textContent = newValue;
|
||
cell.classList.remove('editing');
|
||
}
|
||
|
||
function showAlert(message: string): void {
|
||
// Créer la popup si elle n'existe pas
|
||
let alertPopup = document.querySelector('.alert-popup');
|
||
if (!alertPopup) {
|
||
alertPopup = document.createElement('div');
|
||
alertPopup.className = 'alert-popup';
|
||
document.body.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);
|
||
}
|
||
|
||
// Fonction pour gérer les événements d'édition
|
||
function initializeEventListeners(): void {
|
||
const editableFields = document.querySelectorAll<HTMLElement>('.editable');
|
||
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 = document.getElementById('avatar-upload') as HTMLInputElement;
|
||
if (avatarInput) {
|
||
avatarInput.addEventListener('change', handleAvatarUpload);
|
||
}
|
||
}
|
||
|
||
// Fonction pour gérer le téléchargement de l'avatar
|
||
function 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<FileReader>) => {
|
||
const result = e.target?.result as string;
|
||
const popupAvatar = document.getElementById('popup-avatar-img') as HTMLImageElement;
|
||
const navAvatar = document.querySelector('.nav-wrapper .avatar') as HTMLImageElement;
|
||
|
||
if (popupAvatar) popupAvatar.src = result;
|
||
if (navAvatar) navAvatar.src = result;
|
||
|
||
localStorage.setItem('userAvatar', result);
|
||
};
|
||
reader.readAsDataURL(file);
|
||
}
|
||
}
|
||
|
||
// Initialisation au chargement de la page
|
||
if (!localStorage.getItem('rows')) {
|
||
localStorage.setItem('rows', JSON.stringify(defaultRows));
|
||
}
|
||
|
||
// Event Listeners et initialisation
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
//console.log("DOM Content Loaded");
|
||
initAccount();
|
||
showPairing();
|
||
});
|
||
|
||
|
||
// Ajout des fonctions manquantes
|
||
|
||
|
||
function showProcess(): void {
|
||
//console.log("showProcess called");
|
||
currentMode = 'process';
|
||
hideAllContent();
|
||
|
||
const headerTitle = document.getElementById('header-title');
|
||
if (headerTitle) headerTitle.textContent = 'Process';
|
||
|
||
const processContent = document.getElementById('process-content');
|
||
if (processContent) {
|
||
processContent.style.display = 'block';
|
||
processContent.innerHTML = `
|
||
<div class="parameter-header" id="parameter-header">Process</div>
|
||
<div class="table-container">
|
||
<table class="parameter-table" id="process-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Process Name</th>
|
||
<th>Role</th>
|
||
<th>Notifications</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody></tbody>
|
||
</table>
|
||
</div>
|
||
`;
|
||
|
||
// Utiliser mockProcessRows au lieu du localStorage
|
||
updateProcessTableContent(mockProcessRows);
|
||
}
|
||
}
|
||
|
||
// Fonction utilitaire pour mettre à jour le contenu du tableau Process
|
||
function updateProcessTableContent(rows: any[]): void {
|
||
const tbody = document.querySelector('#process-table tbody');
|
||
if (!tbody) return;
|
||
|
||
tbody.innerHTML = rows.map(row => `
|
||
<tr>
|
||
<td>${row.process}</td>
|
||
<td>${row.role}</td>
|
||
<td>
|
||
<div class="notification-container" onclick="window.showProcessNotifications('${row.process}')">
|
||
<i class="fas fa-bell"></i>
|
||
<span class="notification-count" data-process="${row.process}">
|
||
${row.notification?.messages?.filter((m: any) => !m.read).length || 0}/${row.notification?.messages?.length || 0}
|
||
</span>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
`).join('');
|
||
}
|
||
|
||
|
||
|
||
function 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 => `
|
||
<div class="notification-item ${msg.read ? 'read' : 'unread'}"
|
||
onclick="window.markAsRead('${processName}', ${msg.id}, this)">
|
||
<div class="notification-status">
|
||
<i class="fas ${msg.read ? 'fa-check' : 'fa-circle'}"></i>
|
||
</div>
|
||
<div class="notification-content">
|
||
<span>${msg.message}</span>
|
||
<small>${msg.date}</small>
|
||
</div>
|
||
</div>
|
||
`).join('');
|
||
|
||
if (process.notification.messages.length === 0) {
|
||
notificationsList = '<p>No notifications</p>';
|
||
}
|
||
|
||
modal.innerHTML = `
|
||
<div class="notifications-content">
|
||
<h3>${processName} Notifications</h3>
|
||
<div class="notifications-list">
|
||
${notificationsList}
|
||
</div>
|
||
<button class="close-notifications">x</button>
|
||
</div>
|
||
`;
|
||
|
||
document.body.appendChild(modal);
|
||
|
||
// Mettre à jour le compteur de notifications
|
||
const countElement = document.querySelector(`.notification-count[data-process="${processName}"]`);
|
||
if (countElement) {
|
||
const notifCount = calculateNotifications(process.notification.messages);
|
||
countElement.textContent = `${notifCount.unread}/${notifCount.total}`;
|
||
}
|
||
|
||
const closeButton = modal.querySelector('.close-notifications');
|
||
closeButton?.addEventListener('click', () => {
|
||
modal.remove();
|
||
showProcess(); // Rafraîchir l'affichage pour mettre à jour les compteurs
|
||
});
|
||
}
|
||
|
||
function generateRandomNotification(): void {
|
||
const processes = JSON.parse(localStorage.getItem(STORAGE_KEYS.process) || '[]');
|
||
if (processes.length === 0) return;
|
||
|
||
const randomProcess = processes[Math.floor(Math.random() * processes.length)].column1;
|
||
const notification = {
|
||
message: notificationMessages[Math.floor(Math.random() * notificationMessages.length)],
|
||
timestamp: new Date().toLocaleString(),
|
||
isRead: false
|
||
};
|
||
|
||
if (!mockNotifications[randomProcess]) {
|
||
mockNotifications[randomProcess] = [];
|
||
}
|
||
mockNotifications[randomProcess].push(notification);
|
||
|
||
if (currentMode === 'process') {
|
||
showProcess();
|
||
}
|
||
}
|
||
|
||
function handleLogout(): void {
|
||
localStorage.clear();
|
||
window.location.href = '../login/login.html';
|
||
}
|
||
|
||
|
||
|
||
// Initialisation des notifications
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
loadUserInfo();
|
||
setInterval(generateRandomNotification, 60000);
|
||
});
|
||
|
||
|
||
// Fonctions de gestion des contrats
|
||
function showContractPopup(contractId: string): void {
|
||
const contract = mockContracts[contractId as keyof typeof mockContracts];
|
||
if (!contract) {
|
||
showAlert('Contract not found');
|
||
return;
|
||
}
|
||
|
||
const popupHTML = `
|
||
<div class="contract-popup-overlay">
|
||
<div class="contract-popup-content">
|
||
<button class="close-contract-popup" onclick="this.closest('.contract-popup-overlay').remove()">×</button>
|
||
<div class="contract-header">
|
||
<h2>${contract.title}</h2>
|
||
<div class="contract-date">Date: ${contract.date}</div>
|
||
</div>
|
||
|
||
<div class="contract-parties">
|
||
<strong>Parties involved:</strong>
|
||
<ul>
|
||
${contract.parties.map(party => `<li>${party}</li>`).join('')}
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="contract-terms">
|
||
<strong>Terms and Conditions:</strong>
|
||
<ul>
|
||
${contract.terms.map(term => `<li>${term}</li>`).join('')}
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="contract-content">
|
||
<strong>Details:</strong>
|
||
<p>${contract.content}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
document.body.insertAdjacentHTML('beforeend', popupHTML);
|
||
}
|
||
|
||
// Fonction utilitaire pour cacher tous les contenus
|
||
function hideAllContent(): void {
|
||
const contents = ['pairing-content', 'wallet-content', 'process-content', 'data-content'];
|
||
contents.forEach(id => {
|
||
const element = document.getElementById(id);
|
||
if (element) {
|
||
element.style.display = 'none';
|
||
}
|
||
});
|
||
}
|
||
|
||
// Fonctions d'affichage des sections
|
||
function showPairing(): void {
|
||
|
||
isAddingRow = false;
|
||
currentRow = null;
|
||
|
||
currentMode = 'pairing';
|
||
// Cacher tous les contenus
|
||
hideAllContent();
|
||
|
||
// Mettre à jour le titre
|
||
const headerElement = document.getElementById('parameter-header');
|
||
if (headerElement) {
|
||
headerElement.textContent = 'Pairing';
|
||
}
|
||
|
||
|
||
// Afficher le contenu de pairing
|
||
const pairingContent = document.getElementById('pairing-content');
|
||
|
||
if (pairingContent) {
|
||
pairingContent.style.display = 'block';
|
||
pairingContent.innerHTML = `
|
||
<div class="parameter-header" id="parameter-header">Pairing</div>
|
||
<div class="table-container">
|
||
<table class="parameter-table" id="pairing-table">
|
||
<thead>
|
||
<tr>
|
||
<th>SP Address</th>
|
||
<th>Device Name</th>
|
||
<th>SP Emojis</th>
|
||
<th></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody></tbody>
|
||
</table>
|
||
<div class="button-container">
|
||
<button class="add-row-button button-style" onclick="window.addRow()">Add a line</button>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
// Mettre à jour le contenu du tableau
|
||
const rows = JSON.parse(localStorage.getItem(STORAGE_KEYS.pairing) || '[]');
|
||
updateTableContent(rows);
|
||
}
|
||
}
|
||
|
||
function showWallet(): void {
|
||
isAddingRow = false;
|
||
currentRow = null;
|
||
|
||
currentMode = 'wallet';
|
||
hideAllContent();
|
||
|
||
// Mettre à jour le titre
|
||
const headerTitle = document.getElementById('header-title');
|
||
if (headerTitle) headerTitle.textContent = 'Wallet';
|
||
|
||
const walletContent = document.getElementById('wallet-content');
|
||
if (!walletContent) return;
|
||
walletContent.style.display = 'block'; // Ajout de cette ligne pour rendre visible
|
||
walletContent.innerHTML = `
|
||
<div class="parameter-header" id="parameter-header">Wallet</div>
|
||
<div class="table-container">
|
||
<table class="parameter-table" id="wallet-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Label</th>
|
||
<th>Wallet</th>
|
||
<th>Type</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody></tbody>
|
||
</table>
|
||
<div class="button-container">
|
||
<button class="add-row-button button-style" onclick="addWalletRow()">Add a line</button>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
const rows = JSON.parse(localStorage.getItem(STORAGE_KEYS.wallet) || '[]');
|
||
updateWalletTableContent(rows);
|
||
}
|
||
|
||
|
||
function updateWalletTableContent(rows: WalletRow[]): void {
|
||
const tbody = document.querySelector('#wallet-table tbody');
|
||
if (!tbody) return;
|
||
|
||
tbody.innerHTML = rows.map(row => `
|
||
<tr>
|
||
<td>${row.column1}</td>
|
||
<td>${row.column2}</td>
|
||
<td class="device-name" onclick="editDeviceName(this)">${row.column3}</td>
|
||
</tr>
|
||
`).join('');
|
||
}
|
||
|
||
function showData(): void {
|
||
//console.log("showData called");
|
||
currentMode = 'data';
|
||
hideAllContent();
|
||
|
||
const headerTitle = document.getElementById('header-title');
|
||
if (headerTitle) headerTitle.textContent = 'Data';
|
||
|
||
const dataContent = document.getElementById('data-content');
|
||
if (dataContent) {
|
||
dataContent.style.display = 'block';
|
||
dataContent.innerHTML = `
|
||
<div class="parameter-header" id="parameter-header">Data</div>
|
||
<div class="table-container">
|
||
<table class="parameter-table" id="data-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Name</th>
|
||
<th>Visibility</th>
|
||
<th>Role</th>
|
||
<th>Duration</th>
|
||
<th>Legal</th>
|
||
<th>Contract</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody></tbody>
|
||
</table>
|
||
</div>
|
||
`;
|
||
|
||
const rows = mockDataRows || JSON.parse(localStorage.getItem(STORAGE_KEYS.data) || '[]');
|
||
updateDataTableContent(rows);
|
||
}
|
||
}
|
||
|
||
// Fonctions de gestion du wallet
|
||
function addWalletRow(): void {
|
||
if (isAddingRow) return;
|
||
isAddingRow = true;
|
||
|
||
const table = document.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 = document.querySelector('#wallet-content .button-container');
|
||
if (!buttonContainer) return;
|
||
|
||
buttonContainer.innerHTML = `
|
||
<div class="action-buttons-wrapper">
|
||
<button onclick="confirmWalletRow()" class="action-button confirm-button">✓</button>
|
||
<button onclick="cancelWalletRow()" class="action-button cancel-button">✗</button>
|
||
</div>
|
||
`;
|
||
|
||
updateActionButtons();
|
||
}
|
||
|
||
function 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;
|
||
showWallet();
|
||
} else {
|
||
showAlert('Please complete all fields before confirming.');
|
||
}
|
||
}
|
||
|
||
function 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 = document.querySelector('#wallet-content .button-container');
|
||
if (!buttonContainer) return;
|
||
|
||
buttonContainer.innerHTML = `
|
||
<button class="add-row-button button-style" onclick="window.addWalletRow()">Add a line</button>
|
||
`;
|
||
|
||
|
||
}
|
||
|
||
// Fonctions de sauvegarde
|
||
function saveDataRowToLocalStorage(row: DataRow): void {
|
||
const rows: DataRow[] = JSON.parse(localStorage.getItem(STORAGE_KEYS.data) || '[]');
|
||
rows.push(row);
|
||
localStorage.setItem(STORAGE_KEYS.data, JSON.stringify(rows));
|
||
}
|
||
|
||
function saveDeviceName(cell: HTMLTableCellElement, newValue: string): void {
|
||
const row = cell.closest('tr');
|
||
if (!row) return;
|
||
|
||
const index = Array.from(row.parentElement?.children || []).indexOf(row);
|
||
const rows: Row[] = JSON.parse(localStorage.getItem(STORAGE_KEYS[currentMode]) || '[]');
|
||
|
||
if (rows[index]) {
|
||
rows[index].column3 = newValue;
|
||
localStorage.setItem(STORAGE_KEYS[currentMode], JSON.stringify(rows));
|
||
}
|
||
}
|
||
|
||
function saveRowToLocalStorage(row: Row): void {
|
||
const rows: Row[] = JSON.parse(localStorage.getItem(STORAGE_KEYS[currentMode]) || '[]');
|
||
rows.push(row);
|
||
localStorage.setItem(STORAGE_KEYS[currentMode], JSON.stringify(rows));
|
||
}
|
||
|
||
|
||
// Fonctions de mise à jour de l'interface
|
||
function updateTableContent(rows: Row[]): void {
|
||
const tbody = document.querySelector('#pairing-table tbody');
|
||
if (!tbody) return;
|
||
|
||
tbody.innerHTML = rows.map(row => `
|
||
<tr>
|
||
<td>${row.column1}</td>
|
||
<td class="device-name" onclick="editDeviceName(this)">${row.column2}</td>
|
||
<td>${row.column3}</td>
|
||
<td>
|
||
<button class="delete-button" onclick="deleteRow(this)">
|
||
<i class="fas fa-trash" style="color: red;"></i>
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
`).join('');
|
||
}
|
||
|
||
function updateDataTableContent(rows: DataRow[]): void {
|
||
const tbody = document.querySelector('#data-table tbody');
|
||
if (!tbody) return;
|
||
|
||
tbody.innerHTML = rows.map(row => `
|
||
<tr>
|
||
<td>${row.column1}</td>
|
||
<td>${row.column2}</td>
|
||
<td>${row.column3}</td>
|
||
<td>${row.column4}</td>
|
||
<td>${row.column5}</td>
|
||
<td>
|
||
<a href="#" onclick="showContractPopup('${row.column6}')">${row.column6}</a>
|
||
</td>
|
||
</tr>
|
||
`).join('');
|
||
}
|
||
|
||
// Fonctions de gestion de l'avatar et de la bannière
|
||
function openAvatarPopup(): void {
|
||
const popup = document.getElementById('avatar-popup');
|
||
if (!popup) return;
|
||
|
||
// Récupérer les valeurs stockées
|
||
const savedName = localStorage.getItem('userName') || 'Luke';
|
||
const savedLastName = localStorage.getItem('userLastName') || 'Doe';
|
||
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 = `
|
||
<div class="popup-content">
|
||
<h1>Profile</h1>
|
||
<span class="close-popup">×</span>
|
||
|
||
<div class="banner-container">
|
||
<div class="banner-wrapper">
|
||
<img src="${savedBanner}" alt="Banner" id="popup-banner-img" class="banner-image clickable">
|
||
<input type="file" id="banner-upload" accept="image/*" style="display: none;">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="popup-avatar">
|
||
<label for="avatar-upload" class="avatar-upload-label">
|
||
<img src="${savedAvatar}" alt="Avatar" id="popup-avatar-img">
|
||
<input type="file" id="avatar-upload" accept="image/*" style="display: none;">
|
||
<div class="avatar-overlay">
|
||
<span>Change Avatar</span>
|
||
</div>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="popup-info">
|
||
<div class="info-row">
|
||
<strong>Name:</strong>
|
||
<input type="text" id="userName" value="${savedName}" class="editable">
|
||
</div>
|
||
<div class="info-row">
|
||
<strong>Last Name:</strong>
|
||
<input type="text" id="userLastName" value="${savedLastName}" class="editable">
|
||
</div>
|
||
<div class="info-row">
|
||
<strong>Address:</strong>
|
||
<span>${savedAddress}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="popup-button-container">
|
||
<div class="action-buttons-row">
|
||
<button class="export-btn" onclick="window.exportUserData()">Export User Data</button>
|
||
<button class="export-btn recovery-btn" onclick="window.exportRecovery()">Export Recovery</button>
|
||
<button class="delete-account-btn" onclick="window.confirmDeleteAccount()">Delete Account</button>
|
||
</div>
|
||
<button class="logout-btn" onclick="window.handleLogout()">Log out</button>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
popup.style.display = 'block';
|
||
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();
|
||
});
|
||
}
|
||
|
||
// Après avoir créé le popup, vérifier si recovery a déjà été exporté
|
||
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';
|
||
}
|
||
}
|
||
}
|
||
|
||
function 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<FileReader>) => {
|
||
const result = e.target?.result as string;
|
||
const popupAvatar = document.getElementById('popup-avatar-img') as HTMLImageElement;
|
||
const navAvatar = document.querySelector('.nav-wrapper .avatar') as HTMLImageElement;
|
||
|
||
if (popupAvatar) popupAvatar.src = result;
|
||
if (navAvatar) navAvatar.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<FileReader>) => {
|
||
const result = e.target?.result as string;
|
||
const popupBanner = document.getElementById('popup-banner-img') as HTMLImageElement;
|
||
if (popupBanner) popupBanner.src = result;
|
||
updateNavbarBanner(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', () => {
|
||
localStorage.setItem('userName', nameInput.value);
|
||
const userNameElement = document.querySelector('.user-name');
|
||
if (userNameElement) {
|
||
userNameElement.textContent = nameInput.value;
|
||
}
|
||
});
|
||
}
|
||
|
||
if (lastNameInput) {
|
||
lastNameInput.addEventListener('input', () => {
|
||
const newLastName = lastNameInput.value;
|
||
localStorage.setItem('userLastName', newLastName);
|
||
updateNavbarLastName(newLastName);
|
||
});
|
||
}
|
||
}
|
||
|
||
function closeAvatarPopup(): void {
|
||
const popup = document.querySelector('.avatar-popup');
|
||
if (popup) popup.remove();
|
||
}
|
||
|
||
function saveUserInfo(): void {
|
||
const nameInput = document.querySelector<HTMLInputElement>('#user-name-input');
|
||
if (nameInput) {
|
||
localStorage.setItem('userName', nameInput.value);
|
||
}
|
||
}
|
||
|
||
function saveAvatarToLocalStorage(dataUrl: string): void {
|
||
localStorage.setItem('userAvatar', dataUrl);
|
||
}
|
||
|
||
function loadAvatar(): void {
|
||
const savedAvatar = localStorage.getItem('userAvatar');
|
||
if (savedAvatar) {
|
||
const avatarImg = document.querySelector('.avatar') as HTMLImageElement;
|
||
if (avatarImg) {
|
||
avatarImg.src = savedAvatar;
|
||
}
|
||
}
|
||
}
|
||
|
||
function loadUserInfo(): void {
|
||
const savedName = localStorage.getItem('userName');
|
||
const savedLastName = localStorage.getItem('userLastName');
|
||
|
||
if (savedName) {
|
||
const nameDisplay = document.querySelector('.user-name');
|
||
if (nameDisplay) {
|
||
nameDisplay.textContent = savedName;
|
||
}
|
||
}
|
||
|
||
if (savedLastName) {
|
||
const lastNameDisplay = document.querySelector('.user-lastname');
|
||
if (lastNameDisplay) {
|
||
lastNameDisplay.textContent = savedLastName;
|
||
}
|
||
}
|
||
|
||
loadAvatar();
|
||
loadSavedBanner();
|
||
}
|
||
|
||
|
||
function addressToEmoji(address: string): string {
|
||
// Utiliser l'adresse pour générer un hash déterministe
|
||
let hash = 0;
|
||
for (let i = 0; i < address.length; i++) {
|
||
hash = ((hash << 5) - hash) + address.charCodeAt(i);
|
||
hash = hash & hash;
|
||
}
|
||
|
||
// Utiliser le hash pour sélectionner les emojis
|
||
const emojis = generateEmojiList();
|
||
const selectedEmojis: string[] = [];
|
||
|
||
// Sélectionner 4 emojis basés sur le hash de l'adresse
|
||
for (let i = 0; i < 4; i++) {
|
||
const index = Math.abs(hash + i) % emojis.length;
|
||
selectedEmojis.push(emojis[index]);
|
||
}
|
||
|
||
return selectedEmojis.join('');
|
||
}
|
||
|
||
function isValidRole(role: string): boolean {
|
||
const validRoles = ['admin', 'user', 'guest', 'manager'];
|
||
return validRoles.includes(role.toLowerCase());
|
||
}
|
||
|
||
// Fonction pour annuler l'ajout d'une ligne
|
||
function cancelAddRow(): void {
|
||
if (!currentRow) return;
|
||
currentRow.remove();
|
||
isAddingRow = false;
|
||
currentRow = null;
|
||
|
||
const buttonContainer = document.querySelector('.button-container');
|
||
if (buttonContainer) {
|
||
buttonContainer.innerHTML = `
|
||
<button class="add-row-button button-style" onclick="addRow()">Add a line</button>
|
||
`;
|
||
}
|
||
}
|
||
|
||
// Fonction pour sauvegarder le nom
|
||
function saveName(cell: HTMLElement, input: HTMLInputElement): void {
|
||
const newValue = input.value.trim();
|
||
const originalValue = cell.getAttribute('data-original-value');
|
||
|
||
// Si vide, revenir à la valeur originale
|
||
if (newValue === '') {
|
||
cell.textContent = originalValue;
|
||
return;
|
||
}
|
||
|
||
// Mettre à jour l'affichage
|
||
cell.textContent = newValue;
|
||
|
||
// Mettre à jour le localStorage
|
||
const storageKey = STORAGE_KEYS.data;
|
||
const rows = JSON.parse(localStorage.getItem(storageKey) || '[]');
|
||
|
||
const updatedRows = rows.map((row: any) => {
|
||
if (row.column1 === originalValue) {
|
||
return { ...row, column1: newValue };
|
||
}
|
||
return row;
|
||
});
|
||
|
||
localStorage.setItem(storageKey, JSON.stringify(updatedRows));
|
||
}
|
||
|
||
// Fonction pour mettre à jour le localStorage après suppression
|
||
function updateLocalStorageAfterDelete(index: number): void {
|
||
const rows = JSON.parse(localStorage.getItem(STORAGE_KEYS[currentMode]) || '[]');
|
||
rows.splice(index, 1);
|
||
localStorage.setItem(STORAGE_KEYS[currentMode], JSON.stringify(rows));
|
||
}
|
||
|
||
// Fonction pour désactiver les boutons de suppression
|
||
function disableDeleteButtons(disabled: boolean): void {
|
||
const deleteButtons = document.querySelectorAll<HTMLButtonElement>('.delete-button');
|
||
deleteButtons.forEach(button => {
|
||
button.disabled = disabled;
|
||
button.style.opacity = disabled ? '0.5' : '1';
|
||
button.style.cursor = disabled ? 'not-allowed' : 'pointer';
|
||
});
|
||
}
|
||
|
||
// Fonction pour mettre à jour le contenu de la bannière
|
||
function updateBannerContent(): void {
|
||
const bannerImg = document.getElementById('popup-banner-img') as HTMLImageElement;
|
||
const bannerUpload = document.getElementById('banner-upload') as HTMLInputElement;
|
||
|
||
if (bannerUpload && bannerImg) {
|
||
bannerUpload.addEventListener('change', (e: Event) => {
|
||
const file = (e.target as HTMLInputElement).files?.[0];
|
||
if (file) {
|
||
const reader = new FileReader();
|
||
reader.onload = (e: ProgressEvent<FileReader>) => {
|
||
const result = e.target?.result as string;
|
||
bannerImg.src = result;
|
||
saveBannerToLocalStorage(result);
|
||
updateNavbarBanner(result);
|
||
};
|
||
reader.readAsDataURL(file);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
// Fonction pour générer la liste d'emojis
|
||
function generateEmojiList(): string[] {
|
||
const emojis = ['😀', '😃', '😄', '😁', '😅', '😂', '🤣', '😊', '😇', '🙂', '🙃', '😉'];
|
||
const result: string[] = [];
|
||
|
||
while (result.length < 4) {
|
||
const emoji = emojis[Math.floor(Math.random() * emojis.length)];
|
||
if (!result.includes(emoji)) {
|
||
result.push(emoji);
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
// Fonction pour afficher les notifications
|
||
function showNotifications(processName: string): void {
|
||
const process = mockProcessRows.find(p => p.process === processName);
|
||
if (!process) return;
|
||
|
||
const popupHTML = `
|
||
<div class="notifications-modal">
|
||
<div class="notifications-content">
|
||
<span class="close-button">×</span>
|
||
<h2 class="notifications-title">${processName} Notifications</h2>
|
||
<div class="notifications-list">
|
||
${process.notification.messages.map(msg => `
|
||
<div class="notification-item ${msg.read ? 'read' : 'unread'}">
|
||
<div class="notification-status">
|
||
${msg.read ?
|
||
'<span class="check-icon">✓</span>' :
|
||
'<span class="dot-icon">●</span>'
|
||
}
|
||
</div>
|
||
<div class="notification-content">
|
||
<div class="notification-message">${msg.message}</div>
|
||
<div class="notification-date">${msg.date}</div>
|
||
</div>
|
||
</div>
|
||
`).join('')}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
document.body.insertAdjacentHTML('beforeend', popupHTML);
|
||
|
||
// Event listeners
|
||
const modal = document.querySelector('.notifications-modal');
|
||
const closeBtn = document.querySelector('.close-button');
|
||
|
||
if (modal && closeBtn) {
|
||
modal.addEventListener('click', (e) => {
|
||
if (e.target === modal) {
|
||
modal.remove();
|
||
}
|
||
});
|
||
|
||
closeBtn.addEventListener('click', () => {
|
||
modal.remove();
|
||
});
|
||
}
|
||
}
|
||
|
||
function updateNavbarName(name: string): void {
|
||
const nameElement = document.querySelector('.nav-wrapper .user-name');
|
||
if (nameElement) {
|
||
nameElement.textContent = name;
|
||
}
|
||
}
|
||
|
||
function updateNavbarLastName(lastName: string): void {
|
||
const lastNameElement = document.querySelector('.user-lastname');
|
||
if (lastNameElement) {
|
||
lastNameElement.textContent = lastName;
|
||
}
|
||
}
|
||
|
||
// Ajout des déclarations globales
|
||
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;
|
||
}
|
||
}
|
||
|
||
// Assignation des fonctions à l'objet window
|
||
Object.assign(window, {
|
||
cancelAddRow,
|
||
showContractPopup,
|
||
showPairing,
|
||
showWallet,
|
||
showData,
|
||
addWalletRow,
|
||
confirmWalletRow,
|
||
cancelWalletRow,
|
||
saveDataRowToLocalStorage,
|
||
saveDeviceName,
|
||
saveRowToLocalStorage,
|
||
saveName,
|
||
updateTableContent,
|
||
updateDataTableContent,
|
||
openAvatarPopup,
|
||
closeAvatarPopup,
|
||
saveUserInfo,
|
||
saveAvatarToLocalStorage,
|
||
loadAvatar,
|
||
loadUserInfo,
|
||
updateLocalStorageAfterDelete,
|
||
disableDeleteButtons,
|
||
updateBannerContent,
|
||
generateEmojiList,
|
||
addressToEmoji,
|
||
isValidRole,
|
||
showNotifications,
|
||
confirmDeleteAccount,
|
||
deleteAccount,
|
||
updateNavbarBanner,
|
||
saveBannerToLocalStorage,
|
||
loadSavedBanner,
|
||
closeNotificationPopup,
|
||
markAsRead,
|
||
calculateNotifications,
|
||
exportRecovery,
|
||
exportUserData,
|
||
addRow,
|
||
confirmRow,
|
||
cancelRow,
|
||
deleteRow,
|
||
editDeviceName,
|
||
showAlert,
|
||
initializeEventListeners,
|
||
showProcess,
|
||
showProcessNotifications,
|
||
generateRandomNotification,
|
||
handleLogout,
|
||
updateActionButtons,
|
||
resetButtonContainer,
|
||
finishEditing,
|
||
handleAvatarUpload,
|
||
STORAGE_KEYS,
|
||
ALLOWED_ROLES,
|
||
mockNotifications,
|
||
mockProcessRows,
|
||
mockDataRows,
|
||
mockContracts,
|
||
defaultRows,
|
||
updateNavbarName,
|
||
updateNavbarLastName,
|
||
});
|
||
|
||
// Export des nouvelles fonctions
|
||
export {
|
||
cancelAddRow,
|
||
showContractPopup,
|
||
showPairing,
|
||
showWallet,
|
||
showData,
|
||
addWalletRow,
|
||
confirmWalletRow,
|
||
cancelWalletRow,
|
||
saveDataRowToLocalStorage,
|
||
saveDeviceName,
|
||
saveRowToLocalStorage,
|
||
saveName,
|
||
updateTableContent,
|
||
updateDataTableContent,
|
||
openAvatarPopup,
|
||
closeAvatarPopup,
|
||
saveUserInfo,
|
||
saveAvatarToLocalStorage,
|
||
loadAvatar,
|
||
loadUserInfo,
|
||
updateLocalStorageAfterDelete,
|
||
disableDeleteButtons,
|
||
updateBannerContent,
|
||
generateEmojiList,
|
||
addressToEmoji,
|
||
isValidRole,
|
||
showNotifications,
|
||
confirmDeleteAccount,
|
||
deleteAccount,
|
||
updateNavbarBanner,
|
||
saveBannerToLocalStorage,
|
||
loadSavedBanner,
|
||
closeNotificationPopup,
|
||
markAsRead,
|
||
calculateNotifications,
|
||
exportRecovery,
|
||
exportUserData,
|
||
addRow,
|
||
confirmRow,
|
||
cancelRow,
|
||
deleteRow,
|
||
editDeviceName,
|
||
showAlert,
|
||
initializeEventListeners,
|
||
showProcess,
|
||
showProcessNotifications,
|
||
generateRandomNotification,
|
||
handleLogout,
|
||
updateActionButtons,
|
||
resetButtonContainer,
|
||
finishEditing,
|
||
handleAvatarUpload,
|
||
STORAGE_KEYS,
|
||
ALLOWED_ROLES,
|
||
mockNotifications,
|
||
mockProcessRows,
|
||
mockDataRows,
|
||
mockContracts,
|
||
defaultRows,
|
||
updateNavbarName,
|
||
updateNavbarLastName,
|
||
type Row,
|
||
type Contract,
|
||
type WalletRow,
|
||
type DataRow,
|
||
type Notification,
|
||
type NotificationMessage
|
||
};
|
||
|
||
|
||
// Assignation des fonctions à l'objet window
|
||
window.showNotifications = showNotifications;
|
||
window.closeNotificationPopup = closeNotificationPopup;
|
||
window.markAsRead = markAsRead;
|
||
window.exportRecovery = exportRecovery;
|
||
window.confirmDeleteAccount = confirmDeleteAccount;
|
||
window.deleteAccount = deleteAccount;
|
||
window.updateNavbarBanner = updateNavbarBanner;
|
||
window.saveBannerToLocalStorage = saveBannerToLocalStorage;
|
||
window.loadSavedBanner = loadSavedBanner;
|
||
window.initializeEventListeners = initializeEventListeners;
|
||
window.showProcessNotifications = showProcessNotifications;
|
||
window.handleLogout = handleLogout;
|
||
window.initializeEventListeners = initializeEventListeners;
|
||
window.loadSavedBanner = loadSavedBanner;
|
||
window.initAccount = initAccount;
|
||
window.openAvatarPopup = openAvatarPopup;
|
||
|
||
|
||
// Fonction d'initialisation pour le router
|
||
export function initAccount(): void {
|
||
const savedName = localStorage.getItem('userName') || 'Luke';
|
||
const savedLastName = localStorage.getItem('userLastName') || 'Doe';
|
||
|
||
const userNameElement = document.querySelector('.user-name');
|
||
const userLastNameElement = document.querySelector('.user-lastname');
|
||
|
||
if (userNameElement) {
|
||
userNameElement.textContent = savedName;
|
||
}
|
||
if (userLastNameElement) {
|
||
userLastNameElement.textContent = savedLastName;
|
||
}
|
||
|
||
initializeEventListeners();
|
||
loadSavedBanner();
|
||
if (!localStorage.getItem('rows')) {
|
||
localStorage.setItem('rows', JSON.stringify(defaultRows));
|
||
}
|
||
}
|
||
|
||
// Expose all necessary functions to window
|
||
window.showPairing = showPairing;
|
||
window.showWallet = showWallet;
|
||
window.showProcess = showProcess;
|
||
window.showData = showData;
|
||
|
||
// Initialize when the document is loaded
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
initAccount();
|
||
showPairing();
|
||
});
|
||
|