component_ok
This commit is contained in:
parent
5e1b22d302
commit
6652354b33
@ -595,10 +595,11 @@ body {
|
|||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: calc(100% - 4vh);
|
height: 90vh;
|
||||||
margin-top: 4vh;
|
margin-top: 9vh;
|
||||||
margin-left: -1%;
|
margin-left: -1%;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
width: 209vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Liste des information sur l'account */
|
/* Liste des information sur l'account */
|
||||||
@ -612,6 +613,8 @@ body {
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
border-right: 2px solid #2c3e50;
|
border-right: 2px solid #2c3e50;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
padding-right: 10px;
|
||||||
|
height: 91vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.parameter-list ul {
|
.parameter-list ul {
|
||||||
@ -640,9 +643,10 @@ body {
|
|||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||||||
margin: 10px;
|
margin: 0px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
margin-left: 0%;
|
margin-left: 1%;
|
||||||
|
margin-bottom: -7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* En-tête du parametre */
|
/* En-tête du parametre */
|
||||||
@ -1317,3 +1321,46 @@ body {
|
|||||||
.banner-image.clickable:hover {
|
.banner-image.clickable:hover {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.parameter-list-ul.profile {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
max-height: 200px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.profile-preview {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-banner {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 120px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-banner-img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-info {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px;
|
||||||
|
gap: 10px;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-avatar {
|
||||||
|
width: 45px;
|
||||||
|
height: 45px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid white;
|
||||||
|
}
|
||||||
|
@ -145,10 +145,11 @@ body {
|
|||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: calc(100% - 4vh);
|
height: 90vh;
|
||||||
margin-top: 4vh;
|
margin-top: 9vh;
|
||||||
margin-left: -1%;
|
margin-left: -1%;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
width: 209vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -164,8 +165,8 @@ body {
|
|||||||
border-right: 2px solid #2c3e50;
|
border-right: 2px solid #2c3e50;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
|
height: 91vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-list ul {
|
.group-list ul {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
@ -198,9 +199,10 @@ body {
|
|||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||||||
margin: 10px;
|
margin: 0px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
margin-left: 0%;
|
margin-left: 1%;
|
||||||
|
margin-bottom: -7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* En-tête du chat */
|
/* En-tête du chat */
|
||||||
|
@ -18,6 +18,8 @@ body {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* 4NK NAVBAR */
|
/* 4NK NAVBAR */
|
||||||
|
|
||||||
.brand-logo {
|
.brand-logo {
|
||||||
@ -144,10 +146,11 @@ body {
|
|||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: calc(100% - 4vh);
|
height: 90vh;
|
||||||
margin-top: 4vh;
|
margin-top: 9vh;
|
||||||
margin-left: -1%;
|
margin-left: -1%;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
width: 209vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -163,6 +166,7 @@ body {
|
|||||||
border-right: 2px solid #2c3e50;
|
border-right: 2px solid #2c3e50;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
|
height: 91vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-list ul {
|
.group-list ul {
|
||||||
@ -198,9 +202,10 @@ body {
|
|||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||||||
margin: 10px;
|
margin: 0px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
margin-left: 0%;
|
margin-left: 1%;
|
||||||
|
margin-bottom: -7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* En-tête du chat */
|
/* En-tête du chat */
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
<div class="avatar-section">
|
|
||||||
<img src="https://via.placeholder.com/800x200" alt="Banner" class="banner-image" />
|
|
||||||
<div class="banner-content">
|
|
||||||
<div class="avatar-container">
|
|
||||||
<img src="https://via.placeholder.com/150" alt="Avatar" class="avatar" onclick="window.openAvatarPopup()" />
|
|
||||||
</div>
|
|
||||||
<div class="user-info">
|
|
||||||
<span class="user-name">John</span>
|
|
||||||
<span class="user-lastname">Doe</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,99 +1,10 @@
|
|||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Account</title>
|
<title>Account</title>
|
||||||
<link rel="stylesheet" href="../../public/style/account.css" />
|
</head>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" />
|
<body>
|
||||||
</head>
|
<account-component></account-component>
|
||||||
<body>
|
<script type="module" src="./account.ts"></script>
|
||||||
<!-- Header Container -->
|
</body>
|
||||||
<div id="header-container"></div>
|
|
||||||
|
|
||||||
<!-- Profile Popup -->
|
|
||||||
<div id="avatar-popup" class="popup">
|
|
||||||
<div class="popup-content">
|
|
||||||
<span class="close-popup">×</span>
|
|
||||||
<h2>Profile</h2>
|
|
||||||
|
|
||||||
<!-- Banner Preview Section -->
|
|
||||||
<div class="banner-preview">
|
|
||||||
<div class="banner-image-container">
|
|
||||||
<img src="https://via.placeholder.com/800x200" alt="Banner" class="banner-image" id="popup-banner-img" />
|
|
||||||
<div class="banner-content">
|
|
||||||
<div class="avatar-container">
|
|
||||||
<img src="https://via.placeholder.com/150" alt="Avatar" class="avatar" id="popup-avatar-img" />
|
|
||||||
</div>
|
|
||||||
<div class="user-info">
|
|
||||||
<span class="editable" id="popup-name"></span>
|
|
||||||
<span class="editable" id="popup-lastname"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="banner-controls">
|
|
||||||
<label for="banner-upload" class="banner-upload-label button-style">
|
|
||||||
Change Banner Image
|
|
||||||
<input type="file" id="banner-upload" accept="image/*" style="display: none" />
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Avatar Upload Section -->
|
|
||||||
<div class="popup-avatar">
|
|
||||||
<label for="avatar-upload" class="avatar-upload-label">
|
|
||||||
<img src="https://via.placeholder.com/150" alt="Avatar" class="avatar" id="popup-avatar-img" />
|
|
||||||
<div class="avatar-overlay">
|
|
||||||
<span>Change Avatar</span>
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
<input type="file" id="avatar-upload" accept="image/*" style="display: none" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- User Info Section -->
|
|
||||||
<div class="popup-info">
|
|
||||||
<p><strong>Name:</strong> <span class="editable" id="popup-name"></span></p>
|
|
||||||
<p><strong>Last Name:</strong> <span class="editable" id="popup-lastname"></span></p>
|
|
||||||
<p><strong>Address:</strong> 🏠 🌍 🗽🎊😩-🎊😑🎄😩</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Buttons Container -->
|
|
||||||
<div class="popup-buttons">
|
|
||||||
<button class="delete-account-btn" onclick="confirmDeleteAccount()">Delete Account</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Main Content -->
|
|
||||||
<div class="container">
|
|
||||||
<!-- Parameter List -->
|
|
||||||
<div class="parameter-list">
|
|
||||||
<ul class="parameter-list-ul" onclick="window.showPairing()">
|
|
||||||
Pairing 🔗
|
|
||||||
</ul>
|
|
||||||
<ul class="parameter-list-ul" onclick="window.showWallet()">
|
|
||||||
Wallet 👛
|
|
||||||
</ul>
|
|
||||||
<ul class="parameter-list-ul" onclick="window.showProcess()">
|
|
||||||
Process ⚙️
|
|
||||||
</ul>
|
|
||||||
<ul class="parameter-list-ul" onclick="window.showData()">
|
|
||||||
Data 💾
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Parameter Area -->
|
|
||||||
<div class="parameter-area">
|
|
||||||
<div class="content-container">
|
|
||||||
<div id="pairing-content"></div>
|
|
||||||
<div id="wallet-content"></div>
|
|
||||||
<div id="process-content"></div>
|
|
||||||
<div id="data-content"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Scripts -->
|
|
||||||
<script type="module" src="./account.ts?ts"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,48 +1,13 @@
|
|||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Messagerie</title>
|
|
||||||
<link rel="stylesheet" href="../../public/style/chat.css" />
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
<head>
|
||||||
<!-- Main content-->
|
<title>Chat</title>
|
||||||
<div class="container">
|
</head>
|
||||||
<!-- List of groups -->
|
|
||||||
<div class="group-list">
|
|
||||||
<ul id="group-list">
|
|
||||||
<!-- Groups will be added here dynamically -->
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Chat area -->
|
<body>
|
||||||
<div class="chat-area">
|
<chat-component></chat-component>
|
||||||
<div class="chat-header" id="chat-header">
|
<script type="module" src="./chat.ts"></script>
|
||||||
<!-- Chat title -->
|
</body>
|
||||||
</div>
|
|
||||||
<div class="messages" id="messages">
|
|
||||||
<!-- Messages -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Input area -->
|
|
||||||
<div class="input-area">
|
|
||||||
<label for="file-input" class="attachment-icon">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
|
||||||
<path
|
|
||||||
d="M13.514 2.444l-10.815 10.785c-.449.449-.678 1.074-.625 1.707l.393 4.696c.041.479.422.86.9.9l4.697.394c.633.053 1.258-.177 1.707-.626l11.875-11.844c.196-.196.195-.512 0-.707l-3.536-3.536c-.195-.195-.511-.196-.707 0l-8.878 8.848c-.162.162-.253.382-.253.611v.725c0 .184.148.332.332.332h.725c.229 0 .448-.092.61-.254l7.11-7.08 1.415 1.415-7.386 7.354c-.375.375-.885.586-1.414.586h-2.414c-.555 0-1-.448-1-1v-2.414c0-.53.211-1.039.586-1.414l9.506-9.477c.781-.781 2.049-.781 2.829-.001l4.243 4.243c.391.391.586.902.586 1.414 0 .512-.196 1.025-.587 1.416l-12.35 12.319c-.748.747-1.76 1.164-2.81 1.164-.257 0-6.243-.467-6.499-.487-.664-.052-1.212-.574-1.268-1.267-.019-.242-.486-6.246-.486-6.499 0-1.05.416-2.062 1.164-2.811l10.936-10.936 1.414 1.444z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</label>
|
|
||||||
<input type="file" id="file-input" style="display: none" />
|
|
||||||
|
|
||||||
<textarea id="message-input" rows="3" placeholder="Type your message..."></textarea>
|
|
||||||
|
|
||||||
<button id="send-button">Send</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script type="module" src="./chat.ts?ts"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,171 +1,218 @@
|
|||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
toggleUserList: () => void;
|
toggleUserList: () => void;
|
||||||
switchUser: (userId: string | number) => void;
|
switchUser: (userId: string | number) => void;
|
||||||
loadMemberChat: (memberId: string | number) => void;
|
loadMemberChat: (memberId: string | number) => void;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
import { groupsMock } from '../../mocks/mock-signature/groupsMock';
|
import { groupsMock } from '../../mocks/mock-signature/groupsMock';
|
||||||
import { messagesMock as initialMessagesMock, messagesMock } from '../../mocks/mock-signature/messagesMock';
|
import { messagesMock as initialMessagesMock, messagesMock } from '../../mocks/mock-signature/messagesMock';
|
||||||
import { membersMock } from '../../mocks/mock-signature/membersMocks';
|
import { membersMock } from '../../mocks/mock-signature/membersMocks';
|
||||||
import { Message, DocumentSignature } from '../../models/signature.models';
|
import {
|
||||||
|
Message,
|
||||||
|
DocumentSignature,
|
||||||
|
} from '../../models/signature.models';
|
||||||
import { messageStore } from '../../utils/messageMock';
|
import { messageStore } from '../../utils/messageMock';
|
||||||
import { Member } from '../../interface/memberInterface';
|
import { Member } from '../../interface/memberInterface';
|
||||||
import { Group } from '../../interface/groupInterface';
|
import { Group } from '../../interface/groupInterface';
|
||||||
import { getCorrectDOM } from '../../utils/document.utils';
|
import { getCorrectDOM } from '../../utils/document.utils';
|
||||||
|
import chatStyle from '../../../public/style/chat.css?inline';
|
||||||
|
|
||||||
|
|
||||||
let currentUser: Member = membersMock[0];
|
let currentUser: Member = membersMock[0];
|
||||||
|
|
||||||
interface LocalNotification {
|
interface LocalNotification {
|
||||||
memberId: string;
|
memberId: string;
|
||||||
text: string;
|
text: string;
|
||||||
time: string;
|
time: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initChat() {
|
export function initChat() {
|
||||||
const chatElement = document.createElement('chat-element');
|
const chatElement = document.createElement('chat-element');
|
||||||
const container = document.querySelector('.container');
|
const container = document.querySelector('.container');
|
||||||
if (container) {
|
if (container) {
|
||||||
container.appendChild(chatElement);
|
container.appendChild(chatElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChatElement extends HTMLElement {
|
class ChatElement extends HTMLElement {
|
||||||
private selectedMemberId: string | null = null;
|
private selectedMemberId: string | null = null;
|
||||||
private messagesMock: any[] = [];
|
private messagesMock: any[] = [];
|
||||||
private dom: Node;
|
private dom: Node;
|
||||||
private notifications: LocalNotification[] = [];
|
private notifications: LocalNotification[] = [];
|
||||||
private notificationBadge = document.querySelector('.notification-badge');
|
private notificationBadge = document.querySelector('.notification-badge');
|
||||||
private notificationBoard = document.getElementById('notification-board');
|
private notificationBoard = document.getElementById('notification-board');
|
||||||
private notificationBell = document.getElementById('notification-bell');
|
private notificationBell = document.getElementById('notification-bell');
|
||||||
private selectedSignatories: DocumentSignature[] = [];
|
private selectedSignatories: DocumentSignature[] = [];
|
||||||
private allMembers = membersMock.map((member) => ({
|
private allMembers = membersMock.map(member => ({
|
||||||
id: member.id,
|
id: member.id,
|
||||||
name: member.name,
|
name: member.name,
|
||||||
roleName: 'Default Role',
|
roleName: 'Default Role'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.attachShadow({ mode: 'open' });
|
|
||||||
this.dom = getCorrectDOM('signature-element');
|
|
||||||
|
|
||||||
window.toggleUserList = this.toggleUserList.bind(this);
|
constructor() {
|
||||||
window.switchUser = this.switchUser.bind(this);
|
super();
|
||||||
window.loadMemberChat = this.loadMemberChat.bind(this);
|
this.attachShadow({ mode: 'open' });
|
||||||
|
this.messagesMock = messageStore.getMessages();
|
||||||
|
this.dom = getCorrectDOM('signature-element');
|
||||||
|
|
||||||
// Initialiser les événements de notification
|
this.shadowRoot!.innerHTML = `
|
||||||
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() {
|
<style>
|
||||||
// Pour le bouton Send
|
${chatStyle}
|
||||||
const sendButton = document.getElementById('send-button');
|
</style>
|
||||||
if (sendButton) {
|
<div class="container">
|
||||||
sendButton.addEventListener('click', () => this.sendMessage());
|
<!-- List of groups -->
|
||||||
|
<div class="group-list">
|
||||||
|
<ul id="group-list">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Chat area -->
|
||||||
|
<div class="chat-area">
|
||||||
|
<div class="chat-header" id="chat-header">
|
||||||
|
<!-- Chat title -->
|
||||||
|
</div>
|
||||||
|
<div class="messages" id="messages">
|
||||||
|
<!-- Messages -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Input area -->
|
||||||
|
<div class="input-area">
|
||||||
|
<label for="file-input" class="attachment-icon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||||
|
<path d="M13.514 2.444l-10.815 10.785c-.449.449-.678 1.074-.625 1.707l.393 4.696c.041.479.422.86.9.9l4.697.394c.633.053 1.258-.177 1.707-.626l11.875-11.844c.196-.196.195-.512 0-.707l-3.536-3.536c-.195-.195-.511-.196-.707 0l-8.878 8.848c-.162.162-.253.382-.253.611v.725c0 .184.148.332.332.332h.725c.229 0 .448-.092.61-.254l7.11-7.08 1.415 1.415-7.386 7.354c-.375.375-.885.586-1.414.586h-2.414c-.555 0-1-.448-1-1v-2.414c0-.53.211-1.039.586-1.414l9.506-9.477c.781-.781 2.049-.781 2.829-.001l4.243 4.243c.391.391.586.902.586 1.414 0 .512-.196 1.025-.587 1.416l-12.35 12.319c-.748.747-1.76 1.164-2.81 1.164-.257 0-6.243-.467-6.499-.487-.664-.052-1.212-.574-1.268-1.267-.019-.242-.486-6.246-.486-6.499 0-1.05.416-2.062 1.164-2.811l10.936-10.936 1.414 1.444z"/>
|
||||||
|
</svg>
|
||||||
|
</label>
|
||||||
|
<input type="file" id="file-input" style="display: none;" />
|
||||||
|
<textarea id="message-input" rows="3" placeholder="Type your message..."></textarea>
|
||||||
|
<button id="send-button">Send</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</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();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pour la touche Entrée
|
private initMessageEvents() {
|
||||||
const messageInput = document.getElementById('message-input');
|
// Pour le bouton Send
|
||||||
if (messageInput) {
|
const sendButton = this.shadowRoot?.querySelector('#send-button');
|
||||||
messageInput.addEventListener('keypress', (event: KeyboardEvent) => {
|
if (sendButton) {
|
||||||
if (event.key === 'Enter' && !event.shiftKey) {
|
sendButton.addEventListener('click', () => this.sendMessage());
|
||||||
event.preventDefault();
|
|
||||||
this.sendMessage();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private initFileUpload() {
|
// Pour la touche Entrée
|
||||||
const fileInput = document.getElementById('file-input') as HTMLInputElement;
|
const messageInput = this.shadowRoot?.querySelector('#message-input');
|
||||||
if (fileInput) {
|
if (messageInput) {
|
||||||
fileInput.addEventListener('change', (event: Event) => {
|
messageInput.addEventListener('keypress', (event: Event) => {
|
||||||
const target = event.target as HTMLInputElement;
|
const keyEvent = event as KeyboardEvent; // Cast en KeyboardEvent
|
||||||
if (target.files && target.files.length > 0) {
|
if (keyEvent.key === 'Enter' && !keyEvent.shiftKey) {
|
||||||
this.sendFile(target.files[0]);
|
event.preventDefault();
|
||||||
|
this.sendMessage();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////// 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
|
private initFileUpload() {
|
||||||
this.notifications.forEach((notif, index) => {
|
const fileInput = this.shadowRoot?.querySelector('#file-input') as HTMLInputElement;
|
||||||
const notifElement = document.createElement('div');
|
if (fileInput) {
|
||||||
notifElement.className = 'notification-item';
|
fileInput.addEventListener('change', (event: Event) => {
|
||||||
notifElement.textContent = `${notif.text} at ${notif.time}`;
|
const target = event.target as HTMLInputElement;
|
||||||
notifElement.onclick = () => {
|
if (target.files && target.files.length > 0) {
|
||||||
this.loadMemberChat(notif.memberId);
|
this.sendFile(target.files[0]);
|
||||||
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
|
///////////////////// Notification module /////////////////////
|
||||||
private addNotification(memberId: string, message: Message) {
|
// Delete a notification
|
||||||
// Creating a new notification
|
private removeNotification(index: number) {
|
||||||
const notification = {
|
this.notifications?.splice(index, 1); // Ajout de ?.
|
||||||
memberId,
|
this.renderNotifications();
|
||||||
text: `New message from Member ${memberId}: ${message.text}`,
|
this.updateNotificationBadge();
|
||||||
time: message.time,
|
}
|
||||||
};
|
// Show notifications
|
||||||
|
private renderNotifications() {
|
||||||
|
if (!this.notificationBoard) return;
|
||||||
|
|
||||||
// Added notification to list and interface
|
// Reset the interface
|
||||||
this.notifications.push(notification);
|
this.notificationBoard.innerHTML = '';
|
||||||
this.renderNotifications();
|
|
||||||
this.updateNotificationBadge();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send a messsage
|
// Displays "No notifications available" if there are no notifications
|
||||||
private sendMessage() {
|
if (this.notifications.length === 0) {
|
||||||
const messageInput = document.getElementById('message-input') as HTMLInputElement;
|
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 = this.shadowRoot?.querySelector('#message-input') as HTMLInputElement;
|
||||||
if (!messageInput) return;
|
if (!messageInput) return;
|
||||||
const messageText = messageInput.value.trim();
|
const messageText = messageInput.value.trim();
|
||||||
|
|
||||||
if (messageText === '' || this.selectedMemberId === null) {
|
if (messageText === '' || this.selectedMemberId === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newMessage: Message = {
|
const newMessage: Message = {
|
||||||
id: Date.now(),
|
id: Date.now(),
|
||||||
sender: '4NK',
|
sender: "4NK",
|
||||||
text: messageText,
|
text: messageText,
|
||||||
time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
|
time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
|
||||||
type: 'text' as const,
|
type: 'text' as const
|
||||||
};
|
};
|
||||||
// Add and display the message immediately
|
// Add and display the message immediately
|
||||||
messageStore.addMessage(this.selectedMemberId, newMessage);
|
messageStore.addMessage(this.selectedMemberId, newMessage);
|
||||||
@ -177,223 +224,224 @@ class ChatElement extends HTMLElement {
|
|||||||
|
|
||||||
// Automatic response after 2 seconds
|
// Automatic response after 2 seconds
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (this.selectedMemberId) {
|
if (this.selectedMemberId) {
|
||||||
const autoReply = this.generateAutoReply(`Member ${this.selectedMemberId}`);
|
const autoReply = this.generateAutoReply(`Member ${this.selectedMemberId}`);
|
||||||
messageStore.addMessage(this.selectedMemberId, autoReply);
|
messageStore.addMessage(this.selectedMemberId, autoReply);
|
||||||
this.messagesMock = messageStore.getMessages();
|
this.messagesMock = messageStore.getMessages();
|
||||||
this.loadMemberChat(this.selectedMemberId);
|
this.loadMemberChat(this.selectedMemberId);
|
||||||
this.addNotification(this.selectedMemberId, autoReply);
|
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,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
}, 2000);
|
||||||
});
|
|
||||||
|
|
||||||
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);
|
// Scroll down the conversation after loading messages
|
||||||
}
|
private scrollToBottom(container: Element) {
|
||||||
|
(container as HTMLElement).scrollTop = (container as HTMLElement).scrollHeight;
|
||||||
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
|
// Load the list of members
|
||||||
const roleNameAlt = container.querySelector('.role-name')?.textContent;
|
private loadMemberChat(memberId: string | number) {
|
||||||
console.log('Role name from span:', roleNameAlt);
|
this.selectedMemberId = String(memberId);
|
||||||
|
const memberMessages = this.messagesMock.find(m => String(m.memberId) === String(memberId));
|
||||||
|
|
||||||
if (!container.querySelector('.folder-icon')) {
|
// Find the process and the role of the member
|
||||||
const folderButton = document.createElement('span');
|
let memberInfo = { processName: '', roleName: '', memberName: '' };
|
||||||
folderButton.className = 'folder-icon';
|
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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
folderButton.addEventListener('click', (event) => {
|
const chatHeader = this.shadowRoot?.querySelector('#chat-header');
|
||||||
event.stopPropagation();
|
const messagesContainer = this.shadowRoot?.querySelector('#messages');
|
||||||
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 (!chatHeader || !messagesContainer) return;
|
||||||
if (role) {
|
|
||||||
console.log('Found role:', role);
|
chatHeader.textContent = `Chat with ${memberInfo.roleName} ${memberInfo.memberName} from ${memberInfo.processName}`;
|
||||||
} else {
|
messagesContainer.innerHTML = '';
|
||||||
console.error('Role not found. Name:', roleName);
|
|
||||||
console.error('Available roles:', group.roles);
|
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);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
container.appendChild(folderButton);
|
|
||||||
|
this.scrollToBottom(messagesContainer);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
(roleList as HTMLElement).style.display = (roleList as HTMLElement).style.display === 'none' ? 'block' : 'none';
|
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);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private loadGroupList(): void {
|
|
||||||
const groupList = document.getElementById('group-list');
|
|
||||||
if (!groupList) return;
|
|
||||||
|
|
||||||
groupsMock.forEach((group) => {
|
// Toggle the list of Roles
|
||||||
const li = document.createElement('li');
|
private toggleRoles(group: Group, groupElement: HTMLElement) {
|
||||||
li.className = 'group-list-item';
|
console.log('=== toggleRoles START ===');
|
||||||
|
console.log('Group:', group.name);
|
||||||
|
console.log('Group roles:', group.roles); // Afficher tous les rôles disponibles
|
||||||
|
|
||||||
// Create a flex container for the name and the icon
|
let roleList = groupElement.querySelector('.role-list');
|
||||||
const container = document.createElement('div');
|
console.log('Existing roleList:', roleList);
|
||||||
container.className = 'group-item-container';
|
|
||||||
|
|
||||||
// Span for the process name
|
if (roleList) {
|
||||||
const nameSpan = document.createElement('span');
|
const roleItems = roleList.querySelectorAll('.role-item');
|
||||||
nameSpan.textContent = group.name;
|
roleItems.forEach(roleItem => {
|
||||||
nameSpan.className = 'process-name';
|
console.log('Processing roleItem:', roleItem.innerHTML); // Voir le contenu HTML complet
|
||||||
|
|
||||||
// Add click event to show roles
|
let container = roleItem.querySelector('.role-item-container');
|
||||||
nameSpan.addEventListener('click', (event) => {
|
if (!container) {
|
||||||
event.stopPropagation();
|
container = document.createElement('div');
|
||||||
this.toggleRoles(group, li);
|
container.className = 'role-item-container';
|
||||||
});
|
|
||||||
|
|
||||||
// Assemble the elements
|
// Créer un span pour le nom du rôle
|
||||||
container.appendChild(nameSpan);
|
const nameSpan = document.createElement('span');
|
||||||
li.appendChild(container);
|
nameSpan.className = 'role-name';
|
||||||
|
nameSpan.textContent = roleItem.textContent?.trim() || '';
|
||||||
|
|
||||||
// Create and append the role list container
|
container.appendChild(nameSpan);
|
||||||
const roleList = document.createElement('ul');
|
roleItem.textContent = '';
|
||||||
roleList.className = 'role-list';
|
roleItem.appendChild(container);
|
||||||
roleList.style.display = 'none';
|
}
|
||||||
|
|
||||||
// Add roles for this process
|
// Récupérer le nom du rôle
|
||||||
group.roles.forEach((role) => {
|
const roleName = roleItem.textContent?.trim();
|
||||||
const roleItem = document.createElement('li');
|
console.log('Role name from textContent:', roleName);
|
||||||
roleItem.className = 'role-item';
|
|
||||||
roleItem.textContent = role.name;
|
|
||||||
roleItem.onclick = (event) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
this.toggleMembers(role, roleItem);
|
|
||||||
};
|
|
||||||
roleList.appendChild(roleItem);
|
|
||||||
});
|
|
||||||
|
|
||||||
li.appendChild(roleList);
|
// Alternative pour obtenir le nom du rôle
|
||||||
groupList.appendChild(li);
|
const roleNameAlt = container.querySelector('.role-name')?.textContent;
|
||||||
});
|
console.log('Role name from span:', roleNameAlt);
|
||||||
}
|
|
||||||
|
|
||||||
// Function to manage the list of users
|
if (!container.querySelector('.folder-icon')) {
|
||||||
private toggleUserList() {
|
const folderButton = document.createElement('span');
|
||||||
const userList = getCorrectDOM('userList');
|
folderButton.className = 'folder-icon';
|
||||||
if (!userList) return;
|
|
||||||
|
|
||||||
if (!(userList as HTMLElement).classList.contains('show')) {
|
folderButton.addEventListener('click', (event) => {
|
||||||
(userList as HTMLElement).innerHTML = membersMock
|
event.stopPropagation();
|
||||||
.map(
|
console.log('Clicked role name:', roleName);
|
||||||
(member) => `
|
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 = this.shadowRoot?.querySelector('#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 => `
|
||||||
<div class="user-list-item" onclick="switchUser('${member.id}')">
|
<div class="user-list-item" onclick="switchUser('${member.id}')">
|
||||||
<span class="user-avatar">${member.avatar}</span>
|
<span class="user-avatar">${member.avatar}</span>
|
||||||
<div>
|
<div>
|
||||||
@ -401,127 +449,116 @@ class ChatElement extends HTMLElement {
|
|||||||
<span class="user-email">${member.email}</span>
|
<span class="user-email">${member.email}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`).join('');
|
||||||
)
|
}
|
||||||
.join('');
|
(userList as HTMLElement).classList.toggle('show');
|
||||||
}
|
}
|
||||||
(userList as HTMLElement).classList.toggle('show');
|
|
||||||
}
|
|
||||||
|
|
||||||
private switchUser(userId: string | number) {
|
private switchUser(userId: string | number) {
|
||||||
const user = membersMock.find((member) => member.id === userId);
|
const user = membersMock.find(member => member.id === userId);
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
currentUser = user;
|
currentUser = user;
|
||||||
this.updateCurrentUserDisplay();
|
this.updateCurrentUserDisplay();
|
||||||
const userList = getCorrectDOM('userList') as HTMLElement;
|
const userList = getCorrectDOM('userList') as HTMLElement;
|
||||||
userList?.classList.remove('show');
|
userList?.classList.remove('show');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to update the display of the current user
|
// Function to update the display of the current user
|
||||||
private updateCurrentUserDisplay() {
|
private updateCurrentUserDisplay() {
|
||||||
const userDisplay = getCorrectDOM('current-user') as HTMLElement;
|
const userDisplay = getCorrectDOM('current-user') as HTMLElement;
|
||||||
if (userDisplay) {
|
if (userDisplay) {
|
||||||
userDisplay.innerHTML = `
|
userDisplay.innerHTML = `
|
||||||
<div class="current-user-info">
|
<div class="current-user-info">
|
||||||
<span class="user-avatar">${currentUser.avatar}</span>
|
<span class="user-avatar">${currentUser.avatar}</span>
|
||||||
<span class="user-name">${currentUser.name}</span>
|
<span class="user-name">${currentUser.name}</span>
|
||||||
</div>
|
</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
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// 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
|
// Send a file
|
||||||
private sendFile(file: File) {
|
private sendFile(file: File) {
|
||||||
console.log('SendFile called with file:', file);
|
console.log('SendFile called with file:', file);
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onloadend = () => {
|
reader.onloadend = () => {
|
||||||
const fileData = reader.result;
|
const fileData = reader.result;
|
||||||
const fileName = file.name;
|
const fileName = file.name;
|
||||||
console.log('File loaded:', fileName);
|
console.log('File loaded:', fileName);
|
||||||
|
|
||||||
if (this.selectedMemberId) {
|
if (this.selectedMemberId) {
|
||||||
messageStore.addMessage(this.selectedMemberId, {
|
messageStore.addMessage(this.selectedMemberId, {
|
||||||
id: Date.now(),
|
id: Date.now(),
|
||||||
sender: '4NK',
|
sender: "4NK",
|
||||||
fileName: fileName,
|
fileName: fileName,
|
||||||
fileData: fileData,
|
fileData: fileData,
|
||||||
time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
|
time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
|
||||||
type: 'file',
|
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 => {
|
||||||
});
|
});
|
||||||
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
|
// Gestionnaire d'événements pour le chat
|
||||||
const sendBtn = this.shadowRoot?.querySelector('#send-button');
|
const sendBtn = this.shadowRoot?.querySelector('#send-button');
|
||||||
if (sendBtn) {
|
if (sendBtn) {
|
||||||
sendBtn.addEventListener('click', this.sendMessage.bind(this));
|
sendBtn.addEventListener('click', this.sendMessage.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageInput = this.shadowRoot?.querySelector('#message-input');
|
const messageInput = this.shadowRoot?.querySelector('#message-input');
|
||||||
if (messageInput) {
|
if (messageInput) {
|
||||||
messageInput.addEventListener('keypress', (event: Event) => {
|
messageInput.addEventListener('keypress', (event: Event) => {
|
||||||
if ((event as KeyboardEvent).key === 'Enter') {
|
if ((event as KeyboardEvent).key === 'Enter') {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.sendMessage();
|
this.sendMessage();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gestionnaire pour l'envoi de fichiers
|
// Gestionnaire pour l'envoi de fichiers
|
||||||
const fileInput = this.shadowRoot?.querySelector('#file-input');
|
const fileInput = this.shadowRoot?.querySelector('#file-input');
|
||||||
if (fileInput) {
|
if (fileInput) {
|
||||||
fileInput.addEventListener('change', (event: Event) => {
|
fileInput.addEventListener('change', (event: Event) => {
|
||||||
const file = (event.target as HTMLInputElement).files?.[0];
|
const file = (event.target as HTMLInputElement).files?.[0];
|
||||||
if (file) {
|
if (file) {
|
||||||
this.sendFile(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);
|
connectedCallback() {
|
||||||
this.messagesMock = messageStore.getMessages();
|
this.updateCurrentUserDisplay();
|
||||||
|
this.initializeEventListeners();
|
||||||
|
this.loadGroupList();
|
||||||
|
|
||||||
|
// Si un membre est sélectionné par défaut, charger ses messages
|
||||||
|
if (this.selectedMemberId) {
|
||||||
|
this.loadMemberChat(this.selectedMemberId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.updateCurrentUserDisplay();
|
|
||||||
this.initializeEventListeners();
|
|
||||||
this.loadGroupList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('chat-element', ChatElement);
|
customElements.define('chat-element', ChatElement);
|
||||||
export { ChatElement };
|
export { ChatElement };
|
||||||
|
|
||||||
|
@ -1,59 +1,58 @@
|
|||||||
import { SignatureElement } from './signature';
|
import { SignatureElement } from './signature';
|
||||||
import signatureCss from '../../../public/style/signature.css?raw';
|
import signatureCss from '../../../public/style/signature.css?raw'
|
||||||
import Services from '../../services/service.js';
|
import Services from '../../services/service.js'
|
||||||
|
|
||||||
class SignatureComponent extends HTMLElement {
|
class SignatureComponent extends HTMLElement {
|
||||||
_callback: any;
|
_callback: any
|
||||||
signatureElement: SignatureElement | null = null;
|
signatureElement: SignatureElement | null = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
console.log('INIT');
|
console.log('INIT')
|
||||||
this.attachShadow({ mode: 'open' });
|
this.attachShadow({ mode: 'open' });
|
||||||
|
|
||||||
this.signatureElement = this.shadowRoot?.querySelector('signature-element') || null;
|
this.signatureElement = this.shadowRoot?.querySelector('signature-element') || null;
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
console.log('CALLBACKs');
|
|
||||||
this.render();
|
|
||||||
this.fetchData();
|
|
||||||
|
|
||||||
if (!customElements.get('signature-element')) {
|
|
||||||
customElements.define('signature-element', SignatureElement);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
async fetchData() {
|
connectedCallback() {
|
||||||
if ((import.meta as any).env.VITE_IS_INDEPENDANT_LIB === false) {
|
console.log('CALLBACKs')
|
||||||
const data = await (window as any).myService?.getProcesses();
|
this.render();
|
||||||
} else {
|
this.fetchData();
|
||||||
const service = await Services.getInstance();
|
|
||||||
const data = await service.getProcesses();
|
if (!customElements.get('signature-element')) {
|
||||||
|
customElements.define('signature-element', SignatureElement);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
set callback(fn) {
|
async fetchData() {
|
||||||
if (typeof fn === 'function') {
|
if ((import.meta as any).env.VITE_IS_INDEPENDANT_LIB === false) {
|
||||||
this._callback = fn;
|
const data = await (window as any).myService?.getProcesses();
|
||||||
} else {
|
} else {
|
||||||
console.error('Callback is not a function');
|
const service = await Services.getInstance()
|
||||||
|
const data = await service.getProcesses();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
get callback() {
|
set callback(fn) {
|
||||||
return this._callback;
|
if (typeof fn === 'function') {
|
||||||
}
|
this._callback = fn;
|
||||||
|
} else {
|
||||||
render() {
|
console.error('Callback is not a function');
|
||||||
if (this.shadowRoot) {
|
}
|
||||||
// Créer l'élément signature-element
|
}
|
||||||
const signatureElement = document.createElement('signature-element');
|
|
||||||
this.shadowRoot.innerHTML = `<style>${signatureCss}</style>`;
|
get callback() {
|
||||||
this.shadowRoot.appendChild(signatureElement);
|
return this._callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if(this.shadowRoot) {
|
||||||
|
const signatureElement = document.createElement('signature-element');
|
||||||
|
this.shadowRoot.innerHTML = `<style>${signatureCss}</style>`;
|
||||||
|
this.shadowRoot.appendChild(signatureElement);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { SignatureComponent };
|
export { SignatureComponent }
|
||||||
customElements.define('signature-component', SignatureComponent);
|
customElements.define('signature-component', SignatureComponent);
|
||||||
|
@ -1,46 +1,12 @@
|
|||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
<head>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Signatures</title>
|
<title>Signatures</title>
|
||||||
<link rel="stylesheet" href="../../../public/style/signature.css" />
|
</head>
|
||||||
</head>
|
<body>
|
||||||
|
<signature-component></signature-component>
|
||||||
|
<script type="module" src="./signature.ts"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
<body>
|
|
||||||
<!-- Main content-->
|
|
||||||
<div class="container">
|
|
||||||
<!-- List of groups -->
|
|
||||||
<div class="group-list">
|
|
||||||
<ul id="group-list"></ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Chat area -->
|
|
||||||
<div class="chat-area">
|
|
||||||
<div class="chat-header" id="chat-header">
|
|
||||||
<!-- Chat title -->
|
|
||||||
</div>
|
|
||||||
<div class="messages" id="messages">
|
|
||||||
<!-- Messages -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Input area -->
|
|
||||||
<div class="input-area">
|
|
||||||
<label for="file-input" class="attachment-icon">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
|
||||||
<path
|
|
||||||
d="M13.514 2.444l-10.815 10.785c-.449.449-.678 1.074-.625 1.707l.393 4.696c.041.479.422.86.9.9l4.697.394c.633.053 1.258-.177 1.707-.626l11.875-11.844c.196-.196.195-.512 0-.707l-3.536-3.536c-.195-.195-.511-.196-.707 0l-8.878 8.848c-.162.162-.253.382-.253.611v.725c0 .184.148.332.332.332h.725c.229 0 .448-.092.61-.254l7.11-7.08 1.415 1.415-7.386 7.354c-.375.375-.885.586-1.414.586h-2.414c-.555 0-1-.448-1-1v-2.414c0-.53.211-1.039.586-1.414l9.506-9.477c.781-.781 2.049-.781 2.829-.001l4.243 4.243c.391.391.586.902.586 1.414 0 .512-.196 1.025-.587 1.416l-12.35 12.319c-.748.747-1.76 1.164-2.81 1.164-.257 0-6.243-.467-6.499-.487-.664-.052-1.212-.574-1.268-1.267-.019-.242-.486-6.246-.486-6.499 0-1.05.416-2.062 1.164-2.811l10.936-10.936 1.414 1.444z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</label>
|
|
||||||
<input type="file" id="file-input" style="display: none" />
|
|
||||||
|
|
||||||
<textarea id="message-input" rows="3" placeholder="Type your message..."></textarea>
|
|
||||||
|
|
||||||
<button id="send-button">Send</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script type="module" src="./signature.ts?ts"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user