chat_component_ok
This commit is contained in:
parent
1aac94ce11
commit
0d57a8cbfa
12
src/main.ts
12
src/main.ts
@ -1,10 +1,14 @@
|
||||
import { SignatureComponent } from './pages/signature/signature-component';
|
||||
import { SignatureElement } from './pages/signature/signature';
|
||||
import { ChatComponent } from './pages/chat/chat-component';
|
||||
import { ChatElement } from './pages/chat/chat';
|
||||
|
||||
|
||||
export {
|
||||
SignatureComponent,
|
||||
SignatureElement
|
||||
SignatureElement,
|
||||
ChatComponent,
|
||||
ChatElement
|
||||
};
|
||||
|
||||
|
||||
@ -12,6 +16,8 @@ declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'signature-component': SignatureComponent;
|
||||
'signature-element': SignatureElement;
|
||||
'chat-component': ChatComponent;
|
||||
'chat-element': ChatElement;
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,4 +26,6 @@ if ((import.meta as any).env.VITE_IS_INDEPENDANT_LIB) {
|
||||
// Initialiser les composants si nécessaire
|
||||
customElements.define('signature-component', SignatureComponent);
|
||||
customElements.define('signature-element', SignatureElement);
|
||||
}
|
||||
customElements.define('chat-component', ChatComponent);
|
||||
customElements.define('chat-element', ChatElement);
|
||||
}
|
||||
|
59
src/pages/chat/chat-component.ts
Normal file
59
src/pages/chat/chat-component.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { ChatElement } from './chat';
|
||||
import chatCss from '../../../public/style/chat.css?raw'
|
||||
import Services from '../../services/service.js'
|
||||
|
||||
class ChatComponent extends HTMLElement {
|
||||
_callback: any
|
||||
chatElement: ChatElement | null = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
console.log('INIT')
|
||||
this.attachShadow({ mode: 'open' });
|
||||
|
||||
this.chatElement = this.shadowRoot?.querySelector('chat-element') || null;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
console.log('CALLBACKs')
|
||||
this.render();
|
||||
this.fetchData();
|
||||
|
||||
if (!customElements.get('chat-element')) {
|
||||
customElements.define('chat-element', ChatElement);
|
||||
}
|
||||
}
|
||||
|
||||
async fetchData() {
|
||||
if ((import.meta as any).env.VITE_IS_INDEPENDANT_LIB === false) {
|
||||
const data = await (window as any).myService?.getProcesses();
|
||||
} else {
|
||||
const service = await Services.getInstance()
|
||||
const data = await service.getProcesses();
|
||||
}
|
||||
}
|
||||
|
||||
set callback(fn) {
|
||||
if (typeof fn === 'function') {
|
||||
this._callback = fn;
|
||||
} else {
|
||||
console.error('Callback is not a function');
|
||||
}
|
||||
}
|
||||
|
||||
get callback() {
|
||||
return this._callback;
|
||||
}
|
||||
|
||||
render() {
|
||||
if(this.shadowRoot) {
|
||||
// Créer l'élément chat-element
|
||||
const chatElement = document.createElement('chat-element');
|
||||
this.shadowRoot.innerHTML = `<style>${chatCss}</style>`;
|
||||
this.shadowRoot.appendChild(chatElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { ChatComponent }
|
||||
customElements.define('chat-component', ChatComponent);
|
@ -1,373 +1,536 @@
|
||||
import { groupsMock } from '../../mocks/mock-signature/groupsMock.js';
|
||||
import { messageStore } from '../../utils/messageMock.js';
|
||||
|
||||
let messagesMock = messageStore.getMessages();
|
||||
|
||||
let selectedMemberId: number | null = null;
|
||||
|
||||
// Load the list of groups
|
||||
function loadGroupList() {
|
||||
const groupList = document.getElementById('group-list');
|
||||
if (!groupList) return;
|
||||
|
||||
groupsMock.forEach(group => {
|
||||
const li = document.createElement('li');
|
||||
li.textContent = group.name;
|
||||
li.onclick = (event) => {
|
||||
event.stopPropagation();
|
||||
toggleRoles(group, li);
|
||||
};
|
||||
groupList.appendChild(li);
|
||||
});
|
||||
}
|
||||
|
||||
// Toggle the list of Roles
|
||||
function toggleRoles(group: { roles: { name: string; members: any[] }[] }, groupElement: HTMLElement) {
|
||||
let roleList = groupElement.querySelector('.role-list') as HTMLElement;
|
||||
if (roleList) {
|
||||
roleList.style.display = roleList.style.display === 'none' ? 'block' : 'none';
|
||||
return;
|
||||
declare global {
|
||||
interface Window {
|
||||
toggleUserList: () => void;
|
||||
switchUser: (userId: string | number) => void;
|
||||
loadMemberChat: (memberId: string | number) => void;
|
||||
}
|
||||
|
||||
roleList = document.createElement('ul');
|
||||
roleList.className = 'role-list';
|
||||
|
||||
group.roles.forEach(role => {
|
||||
const roleItem = document.createElement('li');
|
||||
roleItem.textContent = role.name;
|
||||
|
||||
roleItem.onclick = (event) => {
|
||||
event.stopPropagation();
|
||||
toggleMembers(role, roleItem);
|
||||
};
|
||||
|
||||
roleList.appendChild(roleItem);
|
||||
});
|
||||
|
||||
groupElement.appendChild(roleList);
|
||||
}
|
||||
|
||||
// Toggle the list of membres
|
||||
function toggleMembers(role: { members: { id: number; name: string; }[] }, roleElement: HTMLElement) {
|
||||
let memberList = roleElement.querySelector('.member-list') as HTMLElement;
|
||||
if (memberList) {
|
||||
memberList.style.display = memberList.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();
|
||||
loadMemberChat(member.id);
|
||||
};
|
||||
|
||||
memberList.appendChild(memberItem);
|
||||
});
|
||||
|
||||
roleElement.appendChild(memberList);
|
||||
}
|
||||
|
||||
// Load the list of members
|
||||
function loadMemberChat(memberId: string | number) {
|
||||
selectedMemberId = Number(memberId);
|
||||
const memberMessages = messagesMock.find(m => String(m.memberId) === String(memberId));
|
||||
|
||||
// Trouver le processus et le rôle du membre
|
||||
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: {
|
||||
type: string;
|
||||
fileData?: string;
|
||||
fileName?: string;
|
||||
sender: string;
|
||||
text?: string;
|
||||
time: string;
|
||||
}) => {
|
||||
const messageElement = document.createElement('div');
|
||||
messageElement.className = 'message-container';
|
||||
|
||||
const messageContent = document.createElement('div');
|
||||
messageContent.className = 'message';
|
||||
if (message.type === 'file') {
|
||||
messageContent.innerHTML = `<a href="${message.fileData}" download="${message.fileName}" target="_blank">${message.fileName}</a>`;
|
||||
messageContent.classList.add('user');
|
||||
} else {
|
||||
messageContent.innerHTML = `<strong>${message.sender}</strong>: ${message.text} <span style="float: right;">${message.time}</span>`;
|
||||
if (message.sender === "4NK") {
|
||||
messageContent.classList.add('user');
|
||||
}
|
||||
}
|
||||
|
||||
messageElement.appendChild(messageContent);
|
||||
messagesContainer.appendChild(messageElement);
|
||||
});
|
||||
}
|
||||
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';
|
||||
|
||||
|
||||
scrollToBottom(messagesContainer);
|
||||
}
|
||||
let currentUser: Member = membersMock[0];
|
||||
|
||||
// Scroll down the conversation after loading messages
|
||||
function scrollToBottom(container: HTMLElement) {
|
||||
container.scrollTop = container.scrollHeight;
|
||||
}
|
||||
|
||||
// Generate an automatic response
|
||||
function generateAutoReply(senderName: string) {
|
||||
return {
|
||||
id: Date.now(),
|
||||
sender: senderName,
|
||||
text: "OK...",
|
||||
time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
|
||||
type: 'text'
|
||||
};
|
||||
}
|
||||
|
||||
// Send a messsage
|
||||
function sendMessage() {
|
||||
const messageInput = document.getElementById('message-input') as HTMLInputElement;
|
||||
if (!messageInput) return;
|
||||
const messageText = messageInput.value.trim();
|
||||
|
||||
if (messageText === '' || selectedMemberId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newMessage = {
|
||||
id: Date.now(),
|
||||
sender: "4NK",
|
||||
text: messageText,
|
||||
time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
|
||||
type: 'text'
|
||||
};
|
||||
|
||||
// Ajouter et afficher le message immédiatement
|
||||
messageStore.addMessage(selectedMemberId, newMessage);
|
||||
messagesMock = messageStore.getMessages();
|
||||
loadMemberChat(selectedMemberId);
|
||||
|
||||
// Réinitialiser l'input
|
||||
messageInput.value = '';
|
||||
|
||||
// Réponse automatique après 2 secondes
|
||||
setTimeout(() => {
|
||||
if (selectedMemberId === null) return;
|
||||
|
||||
const autoReply = generateAutoReply(`Member ${selectedMemberId}`);
|
||||
messageStore.addMessage(selectedMemberId, autoReply);
|
||||
messagesMock = messageStore.getMessages();
|
||||
loadMemberChat(selectedMemberId);
|
||||
addNotification(selectedMemberId, autoReply);
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
// Add an event for the submit button
|
||||
const sendBtn = document.getElementById('send-button');
|
||||
const messageInput = document.getElementById('message-input');
|
||||
|
||||
if (sendBtn) sendBtn.onclick = sendMessage;
|
||||
if (messageInput) {
|
||||
messageInput.addEventListener('keydown', function (event) {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
sendMessage();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Send a file
|
||||
function sendFile(file: File) {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = function () {
|
||||
const fileData = reader.result;
|
||||
const fileName = file.name;
|
||||
|
||||
const newFileMessage = {
|
||||
id: Date.now(),
|
||||
sender: "4NK",
|
||||
fileName: fileName,
|
||||
fileData: fileData,
|
||||
time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
|
||||
type: 'file'
|
||||
};
|
||||
|
||||
if (selectedMemberId === null) return;
|
||||
messageStore.addMessage(selectedMemberId, newFileMessage);
|
||||
|
||||
messagesMock = messageStore.getMessages();
|
||||
|
||||
if (selectedMemberId !== null) {
|
||||
loadMemberChat(selectedMemberId);
|
||||
}
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
// Managing the sent file
|
||||
document.getElementById('file-input')?.addEventListener('change', function (event: Event) {
|
||||
const file = (event.target as HTMLInputElement).files?.[0];
|
||||
if (file) {
|
||||
sendFile(file);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
///////////////////// Notification module /////////////////////
|
||||
const notificationBadge = document.querySelector('.notification-badge') as HTMLElement;
|
||||
const notificationBoard = document.getElementById('notification-board');
|
||||
const notificationBell = document.getElementById('notification-bell');
|
||||
|
||||
interface Notification {
|
||||
memberId: number;
|
||||
interface LocalNotification {
|
||||
memberId: string;
|
||||
text: string;
|
||||
time: string;
|
||||
}
|
||||
|
||||
let notifications: Notification[] = [];
|
||||
let unreadCount = 0;
|
||||
// Update notification badge
|
||||
function updateNotificationBadge() {
|
||||
if (!notificationBadge) return;
|
||||
const count = notifications.length;
|
||||
notificationBadge.textContent = count > 99 ? '+99' : count.toString();
|
||||
notificationBadge.style.display = count > 0 ? 'block' : 'none';
|
||||
export function initChat() {
|
||||
const chatElement = document.createElement('chat-element');
|
||||
const container = document.querySelector('.container');
|
||||
if (container) {
|
||||
container.appendChild(chatElement);
|
||||
}
|
||||
}
|
||||
|
||||
// Add notification
|
||||
function addNotification(memberId: number, message: { text: string; time: string }) {
|
||||
// Creating a new notification
|
||||
const notification = {
|
||||
memberId,
|
||||
text: `New message from Member ${memberId}: ${message.text}`,
|
||||
time: message.time
|
||||
};
|
||||
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'
|
||||
}));
|
||||
|
||||
// Added notification to list and interface
|
||||
notifications.push(notification);
|
||||
renderNotifications();
|
||||
updateNotificationBadge();
|
||||
}
|
||||
|
||||
// Show notifications
|
||||
function renderNotifications() {
|
||||
if (!notificationBoard) return;
|
||||
|
||||
// Reset the interface
|
||||
notificationBoard.innerHTML = '';
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: 'open' });
|
||||
this.dom = getCorrectDOM('signature-element');
|
||||
|
||||
// Displays "No notifications available" if there are no notifications
|
||||
if (notifications.length === 0) {
|
||||
notificationBoard.innerHTML = '<div class="no-notification">No notifications available</div>';
|
||||
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 = '<div class="no-notification">No notifications available</div>';
|
||||
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;
|
||||
}
|
||||
|
||||
// Add each notification to the list
|
||||
notifications.forEach((notif, index) => {
|
||||
const notifElement = document.createElement('div');
|
||||
notifElement.className = 'notification-item';
|
||||
notifElement.textContent = `${notif.text} at ${notif.time}`;
|
||||
notifElement.onclick = () => {
|
||||
loadMemberChat(notif.memberId);
|
||||
removeNotification(index);
|
||||
};
|
||||
notificationBoard.appendChild(notifElement);
|
||||
});
|
||||
}
|
||||
|
||||
// Delete a notification
|
||||
function removeNotification(index: number) {
|
||||
notifications.splice(index, 1);
|
||||
renderNotifications();
|
||||
updateNotificationBadge();
|
||||
}
|
||||
|
||||
// Adds an event for deploying the notification list
|
||||
if (notificationBell && notificationBoard) {
|
||||
notificationBell.onclick = () => {
|
||||
notificationBoard.style.display = notificationBoard.style.display === 'block' ? 'none' : 'block';
|
||||
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);
|
||||
|
||||
// Close the notification board when clicking outside of it
|
||||
document.addEventListener('click', (event) => {
|
||||
if (notificationBoard && notificationBell &&
|
||||
notificationBoard.style.display === 'block' &&
|
||||
!notificationBoard.contains(event.target as Node) &&
|
||||
!notificationBell.contains(event.target as Node)) {
|
||||
notificationBoard.style.display = 'none';
|
||||
// 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);
|
||||
}
|
||||
});
|
||||
|
||||
// Loads group list at startup
|
||||
//loadGroupList();
|
||||
|
||||
export function initChat(): void {
|
||||
loadGroupList();
|
||||
// Scroll down the conversation after loading messages
|
||||
private scrollToBottom(container: HTMLElement) {
|
||||
container.scrollTop = container.scrollHeight;
|
||||
}
|
||||
|
||||
// Re-initialize event listeners
|
||||
const sendBtn = document.getElementById('send-button');
|
||||
const messageInput = document.getElementById('message-input');
|
||||
const fileInput = document.getElementById('file-input');
|
||||
|
||||
if (sendBtn) sendBtn.onclick = sendMessage;
|
||||
if (messageInput) {
|
||||
messageInput.addEventListener('keydown', function (event) {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
sendMessage();
|
||||
|
||||
// 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 = `<a href="${message.fileData}" download="${message.fileName}" target="_blank">${message.fileName}</a>`;
|
||||
messageContent.classList.add('user');
|
||||
} else {
|
||||
messageContent.innerHTML = `<strong>${message.sender}</strong>: ${message.text} <span style="float: right;">${message.time}</span>`;
|
||||
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);
|
||||
}
|
||||
|
||||
if (fileInput) {
|
||||
fileInput.addEventListener('change', function (event: Event) {
|
||||
const file = (event.target as HTMLInputElement).files?.[0];
|
||||
if (file) {
|
||||
sendFile(file);
|
||||
}
|
||||
|
||||
// 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);
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize notification listeners
|
||||
const notificationBell = document.getElementById('notification-bell');
|
||||
const notificationBoard = document.getElementById('notification-board');
|
||||
|
||||
if (notificationBell && notificationBoard) {
|
||||
notificationBell.onclick = () => {
|
||||
notificationBoard.style.display = notificationBoard.style.display === 'block' ? 'none' : 'block';
|
||||
|
||||
// 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 => `
|
||||
<div class="user-list-item" onclick="switchUser('${member.id}')">
|
||||
<span class="user-avatar">${member.avatar}</span>
|
||||
<div>
|
||||
<span class="user-name">${member.name}</span>
|
||||
<span class="user-email">${member.email}</span>
|
||||
</div>
|
||||
</div>
|
||||
`).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 = `
|
||||
<div class="current-user-info">
|
||||
<span class="user-avatar">${currentUser.avatar}</span>
|
||||
<span class="user-name">${currentUser.name}</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
// 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 = `
|
||||
<div class="container">
|
||||
<div class="group-list">
|
||||
<ul id="group-list"></ul>
|
||||
</div>
|
||||
<div class="chat-area">
|
||||
<!-- ... reste du HTML de signature.html ... -->
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
this.messagesMock = messageStore.getMessages();
|
||||
if (this.messagesMock.length === 0) {
|
||||
messageStore.setMessages(initialMessagesMock);
|
||||
this.messagesMock = messageStore.getMessages();
|
||||
}
|
||||
this.updateCurrentUserDisplay();
|
||||
this.initializeEventListeners();
|
||||
this.loadGroupList();
|
||||
}
|
||||
}
|
||||
|
||||
function saveMessagesToLocalStorage(messages: any[]) {
|
||||
messageStore.setMessages(messages);
|
||||
messagesMock = messageStore.getMessages();
|
||||
}
|
||||
customElements.define('chat-element', ChatElement);
|
||||
export { ChatElement };
|
||||
|
||||
|
@ -518,7 +518,7 @@ class SignatureElement extends HTMLElement {
|
||||
const signButton = !isVierge ? `
|
||||
${totalSignatures > 0 && signedCount < totalSignatures && canSign ? `
|
||||
<button class="sign-button" onclick="signDocument(${document.id}, ${groupId}, true)">
|
||||
Signer le document
|
||||
Sign the document
|
||||
</button>
|
||||
` : ''}
|
||||
` : '';
|
||||
@ -595,7 +595,7 @@ class SignatureElement extends HTMLElement {
|
||||
document.signatures.filter((sig: DocumentSignature) => sig.signed).length < document.signatures.length &&
|
||||
canSign ? `
|
||||
<button class="sign-button" onclick="signDocument(${document.id}, ${groupId}, false)">
|
||||
Signer le document
|
||||
Sign the document
|
||||
</button>
|
||||
` : ''}
|
||||
` : '';
|
||||
@ -1658,59 +1658,6 @@ class SignatureElement extends HTMLElement {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const addMembersBtn = document.getElementById('addMembersBtn');
|
||||
if (addMembersBtn) {
|
||||
addMembersBtn.addEventListener('click', () => {
|
||||
const selectedMembers: string[] = [];
|
||||
|
||||
// Use this.allMembers instead of allMembers
|
||||
const membersToSelect = this.allMembers.map(member => `
|
||||
<div class="member-checkbox">
|
||||
<input type="checkbox" id="member-${member.id}" value="${member.id}">
|
||||
<label for="member-${member.id}">${member.name} (${member.roleName})</label>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
// Create a modal for member selection
|
||||
const modalContent = `
|
||||
<div class="modal">
|
||||
<h4>Select Members</h4>
|
||||
<div>${membersToSelect}</div>
|
||||
<button id="confirmSelectionBtn">Confirm</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Append the modal to the body
|
||||
document.body.insertAdjacentHTML('beforeend', modalContent);
|
||||
|
||||
// Add event for the confirmation button
|
||||
const confirmBtn = document.getElementById('confirmSelectionBtn');
|
||||
if (confirmBtn) {
|
||||
confirmBtn.addEventListener('click', () => {
|
||||
// Retrieve selected members
|
||||
const selectedCheckboxes = document.querySelectorAll('.modal input[type="checkbox"]:checked');
|
||||
selectedCheckboxes.forEach((checkbox: Element) => {
|
||||
selectedMembers.push((checkbox as HTMLInputElement).value);
|
||||
});
|
||||
|
||||
// Add selected members to the list
|
||||
const membersList = document.getElementById('members-list');
|
||||
if (membersList) {
|
||||
selectedMembers.forEach(memberId => {
|
||||
const member = this.allMembers.find((m: {id: number, name: string, roleName: string}) => m.id === parseInt(memberId));
|
||||
if (member) {
|
||||
membersList.insertAdjacentHTML('beforeend', `<div>${member.name} (${member.roleName})</div>`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Close the modal
|
||||
document.querySelector('.modal')?.remove();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Gestionnaire d'événements pour le chat
|
||||
@ -1719,15 +1666,15 @@ class SignatureElement extends HTMLElement {
|
||||
sendBtn.addEventListener('click', this.sendMessage.bind(this));
|
||||
}
|
||||
|
||||
const messageInput = this.shadowRoot?.querySelector('#message-input');
|
||||
if (messageInput) {
|
||||
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');
|
||||
|
@ -69,8 +69,15 @@ async function handleLocation(path: string) {
|
||||
break;
|
||||
|
||||
case 'chat':
|
||||
const { initChat } = await import('./pages/chat/chat');
|
||||
initChat();
|
||||
const { ChatComponent } = await import('./pages/chat/chat-component');
|
||||
const chatContainer = document.querySelector('.group-list');
|
||||
if (chatContainer) {
|
||||
if (!customElements.get('chat-component')) {
|
||||
customElements.define('chat-component', ChatComponent);
|
||||
}
|
||||
const chatComponent = document.createElement('chat-component');
|
||||
chatContainer.appendChild(chatComponent);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'signature':
|
||||
|
Loading…
x
Reference in New Issue
Block a user