declare global {
interface Window {
toggleUserList: () => void;
switchUser: (userId: string | number) => void;
loadMemberChat: (memberId: string | number) => void;
}
}
import { groupsMock } from '../../mocks/mock-signature/groupsMock';
import { messagesMock as initialMessagesMock, messagesMock } from '../../mocks/mock-signature/messagesMock';
import { membersMock } from '../../mocks/mock-signature/membersMocks';
import { Message, DocumentSignature } from '../../models/signature.models';
import { messageStore } from '../../utils/messageMock';
import { Member } from '../../interface/memberInterface';
import { Group } from '../../interface/groupInterface';
import { getCorrectDOM } from '../../utils/document.utils';
let currentUser: Member = membersMock[0];
interface LocalNotification {
memberId: string;
text: string;
time: string;
}
export function initChat() {
const chatElement = document.createElement('chat-element');
const container = document.querySelector('.container');
if (container) {
container.appendChild(chatElement);
}
}
class ChatElement extends HTMLElement {
private selectedMemberId: string | null = null;
private messagesMock: any[] = [];
private dom: Node;
private notifications: LocalNotification[] = [];
private notificationBadge = document.querySelector('.notification-badge');
private notificationBoard = document.getElementById('notification-board');
private notificationBell = document.getElementById('notification-bell');
private selectedSignatories: DocumentSignature[] = [];
private allMembers = membersMock.map((member) => ({
id: member.id,
name: member.name,
roleName: 'Default Role',
}));
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.dom = getCorrectDOM('signature-element');
window.toggleUserList = this.toggleUserList.bind(this);
window.switchUser = this.switchUser.bind(this);
window.loadMemberChat = this.loadMemberChat.bind(this);
// Initialiser les événements de notification
document.addEventListener('click', (event: Event): void => {
if (this.notificationBoard && this.notificationBoard.style.display === 'block' && !this.notificationBoard.contains(event.target as Node) && this.notificationBell && !this.notificationBell.contains(event.target as Node)) {
this.notificationBoard.style.display = 'none';
}
});
this.initMessageEvents();
this.initFileUpload();
}
private initMessageEvents() {
// Pour le bouton Send
const sendButton = document.getElementById('send-button');
if (sendButton) {
sendButton.addEventListener('click', () => this.sendMessage());
}
// Pour la touche Entrée
const messageInput = document.getElementById('message-input');
if (messageInput) {
messageInput.addEventListener('keypress', (event: KeyboardEvent) => {
if (event.key === 'Enter' && !event.shiftKey) {
event.preventDefault();
this.sendMessage();
}
});
}
}
private initFileUpload() {
const fileInput = document.getElementById('file-input') as HTMLInputElement;
if (fileInput) {
fileInput.addEventListener('change', (event: Event) => {
const target = event.target as HTMLInputElement;
if (target.files && target.files.length > 0) {
this.sendFile(target.files[0]);
}
});
}
}
///////////////////// Notification module /////////////////////
// Delete a notification
private removeNotification(index: number) {
this.notifications?.splice(index, 1); // Ajout de ?.
this.renderNotifications();
this.updateNotificationBadge();
}
// Show notifications
private renderNotifications() {
if (!this.notificationBoard) return;
// Reset the interface
this.notificationBoard.innerHTML = '';
// Displays "No notifications available" if there are no notifications
if (this.notifications.length === 0) {
this.notificationBoard.innerHTML = '
No notifications available
';
return;
}
// Add each notification to the list
this.notifications.forEach((notif, index) => {
const notifElement = document.createElement('div');
notifElement.className = 'notification-item';
notifElement.textContent = `${notif.text} at ${notif.time}`;
notifElement.onclick = () => {
this.loadMemberChat(notif.memberId);
this.removeNotification(index);
};
this.notificationBoard?.appendChild(notifElement);
});
}
private updateNotificationBadge() {
if (!this.notificationBadge) return;
const count = this.notifications.length;
this.notificationBadge.textContent = count > 99 ? '+99' : count.toString();
(this.notificationBadge as HTMLElement).style.display = count > 0 ? 'block' : 'none';
}
// Add notification
private addNotification(memberId: string, message: Message) {
// Creating a new notification
const notification = {
memberId,
text: `New message from Member ${memberId}: ${message.text}`,
time: message.time,
};
// Added notification to list and interface
this.notifications.push(notification);
this.renderNotifications();
this.updateNotificationBadge();
}
// Send a messsage
private sendMessage() {
const messageInput = document.getElementById('message-input') as HTMLInputElement;
if (!messageInput) return;
const messageText = messageInput.value.trim();
if (messageText === '' || this.selectedMemberId === null) {
return;
}
const newMessage: Message = {
id: Date.now(),
sender: '4NK',
text: messageText,
time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
type: 'text' as const,
};
// Add and display the message immediately
messageStore.addMessage(this.selectedMemberId, newMessage);
this.messagesMock = messageStore.getMessages();
this.loadMemberChat(this.selectedMemberId);
// Reset the input
messageInput.value = '';
// Automatic response after 2 seconds
setTimeout(() => {
if (this.selectedMemberId) {
const autoReply = this.generateAutoReply(`Member ${this.selectedMemberId}`);
messageStore.addMessage(this.selectedMemberId, autoReply);
this.messagesMock = messageStore.getMessages();
this.loadMemberChat(this.selectedMemberId);
this.addNotification(this.selectedMemberId, autoReply);
}
}, 2000);
}
// Scroll down the conversation after loading messages
private scrollToBottom(container: HTMLElement) {
container.scrollTop = container.scrollHeight;
}
// Load the list of members
private loadMemberChat(memberId: string | number) {
this.selectedMemberId = String(memberId);
const memberMessages = this.messagesMock.find((m) => String(m.memberId) === String(memberId));
// Find the process and the role of the member
let memberInfo = { processName: '', roleName: '', memberName: '' };
groupsMock.forEach((process) => {
process.roles.forEach((role) => {
const member = role.members.find((m) => String(m.id) === String(memberId));
if (member) {
memberInfo = {
processName: process.name,
roleName: role.name,
memberName: member.name,
};
}
});
});
const chatHeader = document.getElementById('chat-header');
const messagesContainer = document.getElementById('messages');
if (!chatHeader || !messagesContainer) return;
chatHeader.textContent = `Chat with ${memberInfo.roleName} ${memberInfo.memberName} from ${memberInfo.processName}`;
messagesContainer.innerHTML = '';
if (memberMessages) {
memberMessages.messages.forEach((message: Message) => {
const messageElement = document.createElement('div');
messageElement.className = 'message-container';
const messageContent = document.createElement('div');
messageContent.className = 'message';
if (message.type === 'file') {
messageContent.innerHTML = `${message.fileName}`;
messageContent.classList.add('user');
} else {
messageContent.innerHTML = `${message.sender}: ${message.text} ${message.time}`;
if (message.sender === '4NK') {
messageContent.classList.add('user');
}
}
messageElement.appendChild(messageContent);
messagesContainer.appendChild(messageElement);
});
}
this.scrollToBottom(messagesContainer);
}
private toggleMembers(role: { members: { id: string | number; name: string }[] }, roleElement: HTMLElement) {
let memberList = roleElement.querySelector('.member-list');
if (memberList) {
(memberList as HTMLElement).style.display = (memberList as HTMLElement).style.display === 'none' ? 'block' : 'none';
return;
}
memberList = document.createElement('ul');
memberList.className = 'member-list';
role.members.forEach((member) => {
const memberItem = document.createElement('li');
memberItem.textContent = member.name;
memberItem.onclick = (event) => {
event.stopPropagation();
this.loadMemberChat(member.id.toString());
};
memberList.appendChild(memberItem);
});
roleElement.appendChild(memberList);
}
// Toggle the list of Roles
private toggleRoles(group: Group, groupElement: HTMLElement) {
console.log('=== toggleRoles START ===');
console.log('Group:', group.name);
console.log('Group roles:', group.roles); // Afficher tous les rôles disponibles
let roleList = groupElement.querySelector('.role-list');
console.log('Existing roleList:', roleList);
if (roleList) {
const roleItems = roleList.querySelectorAll('.role-item');
roleItems.forEach((roleItem) => {
console.log('Processing roleItem:', roleItem.innerHTML); // Voir le contenu HTML complet
let container = roleItem.querySelector('.role-item-container');
if (!container) {
container = document.createElement('div');
container.className = 'role-item-container';
// Créer un span pour le nom du rôle
const nameSpan = document.createElement('span');
nameSpan.className = 'role-name';
nameSpan.textContent = roleItem.textContent?.trim() || '';
container.appendChild(nameSpan);
roleItem.textContent = '';
roleItem.appendChild(container);
}
// Récupérer le nom du rôle
const roleName = roleItem.textContent?.trim();
console.log('Role name from textContent:', roleName);
// Alternative pour obtenir le nom du rôle
const roleNameAlt = container.querySelector('.role-name')?.textContent;
console.log('Role name from span:', roleNameAlt);
if (!container.querySelector('.folder-icon')) {
const folderButton = document.createElement('span');
folderButton.className = 'folder-icon';
folderButton.addEventListener('click', (event) => {
event.stopPropagation();
console.log('Clicked role name:', roleName);
console.log(
'Available roles:',
group.roles.map((r) => r.name),
);
const role = group.roles.find((r) => r.name === roleName);
if (role) {
console.log('Found role:', role);
} else {
console.error('Role not found. Name:', roleName);
console.error('Available roles:', group.roles);
}
});
container.appendChild(folderButton);
}
});
(roleList as HTMLElement).style.display = (roleList as HTMLElement).style.display === 'none' ? 'block' : 'none';
}
}
private loadGroupList(): void {
const groupList = document.getElementById('group-list');
if (!groupList) return;
groupsMock.forEach((group) => {
const li = document.createElement('li');
li.className = 'group-list-item';
// Create a flex container for the name and the icon
const container = document.createElement('div');
container.className = 'group-item-container';
// Span for the process name
const nameSpan = document.createElement('span');
nameSpan.textContent = group.name;
nameSpan.className = 'process-name';
// Add click event to show roles
nameSpan.addEventListener('click', (event) => {
event.stopPropagation();
this.toggleRoles(group, li);
});
// Assemble the elements
container.appendChild(nameSpan);
li.appendChild(container);
// Create and append the role list container
const roleList = document.createElement('ul');
roleList.className = 'role-list';
roleList.style.display = 'none';
// Add roles for this process
group.roles.forEach((role) => {
const roleItem = document.createElement('li');
roleItem.className = 'role-item';
roleItem.textContent = role.name;
roleItem.onclick = (event) => {
event.stopPropagation();
this.toggleMembers(role, roleItem);
};
roleList.appendChild(roleItem);
});
li.appendChild(roleList);
groupList.appendChild(li);
});
}
// Function to manage the list of users
private toggleUserList() {
const userList = getCorrectDOM('userList');
if (!userList) return;
if (!(userList as HTMLElement).classList.contains('show')) {
(userList as HTMLElement).innerHTML = membersMock
.map(
(member) => `
${member.avatar}
${member.name}
${member.email}
`,
)
.join('');
}
(userList as HTMLElement).classList.toggle('show');
}
private switchUser(userId: string | number) {
const user = membersMock.find((member) => member.id === userId);
if (!user) return;
currentUser = user;
this.updateCurrentUserDisplay();
const userList = getCorrectDOM('userList') as HTMLElement;
userList?.classList.remove('show');
}
// Function to update the display of the current user
private updateCurrentUserDisplay() {
const userDisplay = getCorrectDOM('current-user') as HTMLElement;
if (userDisplay) {
userDisplay.innerHTML = `
${currentUser.avatar}
${currentUser.name}
`;
}
}
// Generate an automatic response
private generateAutoReply(senderName: string): Message {
return {
id: Date.now(),
sender: senderName,
text: 'OK...',
time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
type: 'text' as const,
};
}
// Send a file
private sendFile(file: File) {
console.log('SendFile called with file:', file);
const reader = new FileReader();
reader.onloadend = () => {
const fileData = reader.result;
const fileName = file.name;
console.log('File loaded:', fileName);
if (this.selectedMemberId) {
messageStore.addMessage(this.selectedMemberId, {
id: Date.now(),
sender: '4NK',
fileName: fileName,
fileData: fileData,
time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
type: 'file',
});
console.log('Message added to store');
this.messagesMock = messageStore.getMessages();
this.loadMemberChat(this.selectedMemberId);
}
};
reader.readAsDataURL(file);
}
private initializeEventListeners() {
document.addEventListener('DOMContentLoaded', (): void => {});
// Gestionnaire d'événements pour le chat
const sendBtn = this.shadowRoot?.querySelector('#send-button');
if (sendBtn) {
sendBtn.addEventListener('click', this.sendMessage.bind(this));
}
const messageInput = this.shadowRoot?.querySelector('#message-input');
if (messageInput) {
messageInput.addEventListener('keypress', (event: Event) => {
if ((event as KeyboardEvent).key === 'Enter') {
event.preventDefault();
this.sendMessage();
}
});
}
// Gestionnaire pour l'envoi de fichiers
const fileInput = this.shadowRoot?.querySelector('#file-input');
if (fileInput) {
fileInput.addEventListener('change', (event: Event) => {
const file = (event.target as HTMLInputElement).files?.[0];
if (file) {
this.sendFile(file);
}
});
}
}
connectedCallback() {
if (this.shadowRoot) {
this.shadowRoot.innerHTML = `
`;
}
this.messagesMock = messageStore.getMessages();
if (this.messagesMock.length === 0) {
messageStore.setMessages(initialMessagesMock);
this.messagesMock = messageStore.getMessages();
}
this.updateCurrentUserDisplay();
this.initializeEventListeners();
this.loadGroupList();
}
}
customElements.define('chat-element', ChatElement);
export { ChatElement };