import { g as getCorrectDOM } from './document.utils-SxcZpxzG.mjs';
import { S as Services } from './index-C1Gp83RD.mjs';
const signatureStyle = "/* Styles de base */\n:root {\n --primary-color: #3A506B;\n /* Bleu métallique */\n --secondary-color: #B0BEC5;\n /* Gris acier */\n --accent-color: #D68C45;\n /* Cuivre */\n}\n\nbody {\n font-family: Arial, sans-serif;\n margin: 0;\n padding: 0;\n display: flex;\n height: 100vh;\n background-color: #e9edf1;\n flex-direction: column;\n}\n\n\n\n/* 4NK NAVBAR */\n\n.brand-logo {\n text-align: center;\n font-size: 1.5em;\n font-weight: bold;\n}\n\n.nav-wrapper {\n position: fixed;\n background: radial-gradient(circle, white, var(--primary-color));\n display: flex;\n justify-content: space-between;\n align-items: center;\n color: #37474F;\n height: 9vh;\n width: 100vw;\n left: 0;\n top: 0;\n box-shadow: 0px 8px 10px -5px rgba(0, 0, 0, .2), 0px 16px 24px 2px rgba(0, 0, 0, .14), 0px 6px 30px 5px rgba(0, 0, 0, .12);\n}\n\n/* Icônes de la barre de navigation */\n.nav-right-icons {\n display: flex;\n}\n\n.notification-bell,\n.burger-menu {\n height: 20px;\n width: 20px;\n margin-right: 1rem;\n cursor: pointer;\n}\n\n.notification-container {\n position: relative;\n /* Conserve la position pour le notification-board */\n display: inline-flex;\n align-items: center;\n}\n\n.notification-board {\n position: absolute;\n /* Position absolue pour le placer par rapport au container */\n top: 40px;\n right: 0;\n background-color: white;\n border: 1px solid #ccc;\n padding: 10px;\n width: 200px;\n max-height: 300px;\n overflow-y: auto;\n /* Scroll si les notifications dépassent la taille */\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n z-index: 10;\n /* Définit la priorité d'affichage au-dessus des autres éléments */\n display: none;\n /* Par défaut, la notification est masquée */\n}\n\n.notification-item{\n cursor: pointer;\n}\n\n.notification-badge {\n position: absolute;\n top: -18px;\n right: 35px;\n background-color: red;\n color: white;\n border-radius: 50%;\n padding: 4px 8px;\n font-size: 12px;\n display: none;\n /* S'affiche seulement lorsqu'il y a des notifications */\n z-index: 10;\n}\n\n/* Par défaut, le menu est masqué */\n#menu {\n display: none;\n /* Menu caché par défaut */\n transition: display 0.3s ease-in-out;\n}\n\n.burger-menu {\n cursor: pointer;\n}\n\n/* Icône burger */\n#burger-icon {\n cursor: pointer;\n}\n\n.menu-content {\n display: none;\n position: absolute;\n top: 3.4rem;\n right: 1rem;\n background-color: white;\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n border-radius: 5px;\n overflow: hidden;\n}\n\n.menu-content a {\n display: block;\n padding: 10px 20px;\n text-decoration: none;\n color: #333;\n border-bottom: 1px solid #e0e0e0;\n\n &:hover {\n background-color: rgba(26, 28, 24, .08);\n }\n}\n\n.menu-content a:last-child {\n border-bottom: none;\n}\n\n/* Ajustement pour la barre de navigation fixe */\n.container {\n display: flex;\n flex: 1;\n height: 90vh;\n margin-top: 9vh;\n margin-left: -1%;\n text-align: left;\n width: 209vh;\n}\n\n\n/* Liste des groupes */\n\n.group-list {\n width: 25%;\n background-color: #1f2c3d;\n color: white;\n padding: 20px;\n box-sizing: border-box;\n overflow-y: auto;\n border-right: 2px solid #2c3e50;\n flex-shrink: 0;\n padding-right: 10px;\n height: 91vh;\n}\n\n.group-list ul {\n cursor: pointer;\n list-style: none;\n padding: 0;\n padding-right: 10px;\n margin-left: 20px;\n}\n\n.group-list li {\n margin-bottom: 10px;\n padding: 15px;\n border-radius: 8px;\n background-color: #273646;\n cursor: pointer;\n transition: background-color 0.3s, box-shadow 0.3s;\n}\n\n.group-list li:hover {\n background-color: #34495e;\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);\n}\n\n\n/* Zone de chat */\n\n.chat-area {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-width: 0;\n background-color: #ffffff;\n border-radius: 10px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);\n margin: 0px;\n margin-top: 20px;\n margin-left: 1%;\n margin-bottom: -7px;\n}\n\n/* En-tête du chat */\n.chat-header {\n background-color: #34495e;\n color: white;\n padding: 15px;\n font-size: 20px;\n font-weight: bold;\n border-radius: 10px 10px 0 0;\n text-align: center;\n}\n\n/* Messages */\n.messages {\n flex: 1;\n padding: 20px;\n overflow-y: auto;\n background-color: #f1f1f1;\n border-top: 1px solid #ddd;\n}\n\n.message-container {\n max-width: 100%;\n border-radius: 5px;\n overflow-wrap: break-word;\n word-wrap: break-word;\n background-color: #f1f1f1;\n display: flex; \n flex-direction: column; \n}\n\n.message-container .message {\n align-self: flex-start; \n}\n\n.message-container .message.user {\n align-self: flex-end; \n margin-left: auto; \n color: white;\n}\n\n.message {\n padding: 12px 18px;\n background-color: #e1e1e1;\n border-radius: 15px;\n max-width: 70%;\n font-size: 16px;\n line-height: 1.4;\n margin-bottom: 0%;\n white-space: pre-wrap;\n word-wrap: break-word;\n position: relative;\n display: inline-block;\n}\n\n/* Messages de l'utilisateur */\n.message.user {\n background-color: #3498db;\n color: white;\n align-self: flex-end;\n text-align: right;\n}\n\n/* Amélioration de l'esthétique des messages */\n/* .message.user:before {\n content: '';\n position: absolute;\n top: 10px;\n right: -10px;\n border: 10px solid transparent;\n border-left-color: #3498db;\n} */\n\n/* Zone de saisie */\n.input-area {\n padding: 10px;\n background-color: #bdc3c7;\n display: flex;\n align-items: center;\n /* Alignement vertical */\n}\n\n.input-area input[type=\"text\"] {\n flex: 1;\n /* Prend l'espace restant */\n padding: 10px;\n border: 1px solid #ccc;\n border-radius: 5px;\n}\n\n.input-area .attachment-icon {\n margin: 0 10px;\n cursor: pointer;\n display: flex;\n align-items: center;\n}\n\n.input-area button {\n padding: 10px;\n margin-left: 10px;\n background-color: #2980b9;\n color: white;\n border: none;\n border-radius: 5px;\n cursor: pointer;\n}\n\n.input-area button:hover {\n background-color: #1f608d;\n}\n\n#message-input {\n width: 100%;\n height: 50px;\n resize: none;\n padding: 10px;\n box-sizing: border-box;\n overflow: auto;\n max-width: 100%;\n border-radius: 10px;\n}\n\n/* Responsive */\n@media screen and (max-width: 768px) {\n .group-list {\n display: none;\n /* Masquer la liste des groupes sur les petits écrans */\n }\n\n .chat-area {\n margin: 0;\n }\n}\n\n#process-details {\n flex: 1;\n background: white;\n border-radius: 8px;\n margin: 10px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n display: none;\n overflow: hidden;\n}\n\n.process-details-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 20px;\n background: #f8f9fa;\n border-bottom: 1px solid #eee;\n border-radius: 8px 8px 0 0;\n}\n\n.process-details-header h2 {\n margin: 0;\n color: #333;\n}\n\n.close-btn {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #666;\n}\n\n.close-btn:hover {\n color: #333;\n}\n\n.process-details-content {\n padding: 20px;\n overflow-y: auto;\n height: calc(100% - 70px);\n}\n\n.details-section {\n margin-bottom: 30px;\n}\n\n.details-section h3 {\n color: #444;\n margin-bottom: 15px;\n padding-bottom: 8px;\n border-bottom: 2px solid #f0f0f0;\n}\n\n.documents-list {\n list-style: none;\n padding: 0;\n}\n\n.documents-list li {\n padding: 8px 0;\n border-bottom: 1px solid #eee;\n}\n\n.roles-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));\n gap: 20px;\n}\n\n.role-block {\n background: #f8f9fa;\n border-radius: 8px;\n padding: 15px;\n border: 1px solid #eee;\n}\n\n.role-block h4 {\n color: #555;\n margin: 0 0 10px 0;\n padding-bottom: 8px;\n border-bottom: 1px solid #eee;\n}\n\n.members-list {\n list-style: none;\n padding: 0;\n}\n\n.members-list li {\n padding: 8px 12px;\n margin: 4px 0;\n cursor: pointer;\n border-radius: 4px;\n transition: background-color 0.2s;\n}\n\n.members-list li:hover {\n background-color: #e9ecef;\n}\n\n.group-list-item {\n padding: 8px 16px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n\n.group-item-container {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n}\n\n.process-name {\n flex-grow: 1;\n cursor: pointer;\n}\n\n.settings-icon {\n cursor: pointer;\n padding: 5px 8px;\n margin-left: 10px;\n border-radius: 4px;\n}\n\n.settings-icon:hover {\n background-color: rgba(255, 255, 255, 0.1);\n}\n\n.process-details {\n position: fixed;\n top: 9vh;\n right: 0;\n bottom: 0;\n left: 23.5%;\n background-color: white;\n box-sizing: border-box;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n border-radius: 8px;\n margin: 10px;\n z-index: 990;\n}\n\n.process-details-content {\n height: calc(100% - 60px); /* Ajusté pour tenir compte du header */\n overflow-y: auto;\n padding: 20px;\n}\n\n.documents-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 20px;\n margin-top: 15px;\n}\n\n.document-card {\n background: white;\n border-radius: 8px;\n padding: 15px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n border: 1px solid #eee;\n}\n\n.document-card.public {\n border-left: 4px solid #4CAF50;\n}\n\n.document-card.private {\n border-left: 4px solid #FFC107;\n}\n\n.document-card.confidential {\n border-left: 4px solid #F44336;\n}\n\n.document-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 10px;\n padding-bottom: 10px;\n border-bottom: 1px solid #eee;\n}\n\n.document-header h4 {\n margin: 0;\n color: #333;\n}\n\n.document-visibility {\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 12px;\n font-weight: bold;\n}\n\n.public .document-visibility {\n background-color: #E8F5E9;\n color: #2E7D32;\n}\n\n.private .document-visibility {\n background-color: #FFF3E0;\n color: #F57C00;\n}\n\n.confidential .document-visibility {\n background-color: #FFEBEE;\n color: #C62828;\n}\n\n.document-info {\n margin: 10px 0;\n font-size: 14px;\n color: #666;\n}\n\n.document-info p {\n margin: 5px 0;\n}\n\n.signatures-list {\n margin-top: 10px;\n}\n\n.signature-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px;\n border-radius: 4px;\n margin: 5px 0;\n background-color: #f8f9fa;\n}\n\n.signature-item.signed {\n background-color: #E8F5E9;\n}\n\n.signature-item.pending {\n background-color: #FFF3E0;\n}\n\n.signer-name {\n font-weight: 500;\n}\n\n.signature-status {\n font-size: 12px;\n}\n\n.signed .signature-status {\n color: #2E7D32;\n}\n\n.pending .signature-status {\n color: #F57C00;\n}\n\n.user-selector {\n position: relative;\n margin-right: 20px;\n}\n\n#userSwitchBtn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 8px 12px;\n border-radius: 4px;\n display: flex;\n align-items: center;\n color: var(--primary-color);\n}\n\n#userSwitchBtn:hover {\n background-color: rgba(0, 0, 0, 0.05);\n}\n\n.current-user-info {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.user-avatar {\n background-color: var(--primary-color);\n color: white;\n width: 32px;\n height: 32px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: bold;\n}\n\n.user-list {\n position: absolute;\n top: 100%;\n right: 0;\n background: white;\n border-radius: 4px;\n box-shadow: 0 2px 10px rgba(0,0,0,0.1);\n display: none;\n z-index: 1000;\n max-height: 400px;\n overflow-y: auto;\n width: 250px;\n}\n\n.user-list.show {\n display: block;\n}\n\n.user-list-item {\n padding: 8px 16px;\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n}\n\n.user-list-item:hover {\n background-color: rgba(0, 0, 0, 0.05);\n}\n\n.user-list-item .user-avatar {\n width: 24px;\n height: 24px;\n font-size: 12px;\n}\n\n.user-list-item .user-email {\n font-size: 12px;\n color: #666;\n display: block;\n}\n\n.document-card {\n margin-bottom: 20px;\n padding: 10px;\n border: 1px solid #ccc;\n border-radius: 5px;\n}\n\n.progress-bar {\n background-color: #f3f3f3;\n border-radius: 5px;\n height: 10px;\n width: 100%;\n margin-top: 5px;\n}\n\n.progress {\n background-color: #4caf50; /* Couleur de la barre de progression */\n height: 100%;\n border-radius: 5px;\n}\n\n.new-request-btn {\n background-color: #4caf50; \n color: white; \n border: none;\n border-radius: 5px; \n padding: 10px 15px; \n cursor: pointer; \n margin-left: 10px;\n}\n\n.new-request-btn:hover {\n background-color: #45a049; \n}\n\n.header-buttons {\n display: flex;\n align-items: center; \n gap: 10px; \n}\n\n.close-btn {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #666;\n}\n\n.close-btn:hover {\n color: #333;\n}\n\n.new-request-view {\n padding: 20px;\n background-color: white;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n margin: 20px;\n}\n\n.upload-area {\n border: 2px dashed #ccc;\n padding: 20px;\n text-align: center;\n margin: 20px 0;\n}\n\n.upload-icon {\n font-size: 50px;\n margin: 10px 0;\n}\n\n/* New Request View */\n.new-request-view {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: white;\n z-index: 1000; \n padding: 20px;\n box-sizing: border-box;\n overflow-y: auto;\n}\n\n.upload-area {\n border: 2px dashed #ccc;\n padding: 40px;\n text-align: center;\n margin: 20px auto;\n max-width: 600px;\n background-color: #f9f9f9;\n border-radius: 8px;\n cursor: pointer;\n}\n\n.upload-icon {\n font-size: 50px;\n margin: 20px 0;\n}\n\n.new-request-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-top: 60px;\n padding: 0 20px;\n}\n\n.upload-area {\n border: 2px dashed #ccc;\n padding: 40px;\n text-align: center;\n margin: 20px auto;\n max-width: 600px;\n background-color: #f9f9f9;\n border-radius: 8px;\n cursor: pointer;\n}\n\n.details-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n background-color: #f8f9fa;\n padding: 5px 20px;\n border-radius:20px;\n}\n\n.header-buttons {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-direction: row; \n}\n\n.close-btn {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #666;\n padding: 5px;\n}\n\n.close-btn:hover {\n color: #333;\n}\n\n.new-request-btn {\n background-color: #4caf50;\n color: white;\n border: none;\n border-radius: 5px;\n padding: 8px 16px;\n cursor: pointer;\n /* margin-left: 10px; <- Supprimez cette ligne si elle existe */\n}\n\n.new-request-btn:hover {\n background-color: #45a049;\n}\n\n/* Ajoutez ces styles à votre fichier CSS existant */\n.document-card.vierge {\n background-color: #fff3cd;\n border: 2px solid #ffeeba;\n}\n\n.document-card.vierge .document-header {\n background-color: #fff3cd;\n}\n\n.document-card.vierge h4 {\n color: #856404;\n}\n\n.document-card.vierge .document-info {\n color: #856404;\n}\n\n/* Style pour l'emoji d'avertissement */\n.document-card.vierge h4::before {\n margin-right: 8px;\n}\n\n.vierge-documents-container {\n padding: 20px;\n overflow-y: auto;\n max-height: calc(100vh - 150px);\n}\n\n.document-form {\n padding: 15px;\n background-color: #fff;\n border-radius: 0 0 5px 5px;\n display: flex;\n gap: 20px;\n}\n\n.form-left {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 15px;\n}\n\n.form-right {\n display: flex;\n flex-direction: column;\n align-items: flex-end; /* Aligner le bouton à droite */\n}\n\n.form-group {\n flex: 2;\n display: flex;\n flex-direction: column;\n margin-bottom: 15px;\n}\n\n.form-group-members {\n flex: 2;\n display: flex;\n flex-direction: column;\n margin-bottom: 15px;\n font-weight: bold;\n}\n\n.submit-btn {\n background-color: #4caf50; \n color: white; \n border: none;\n border-radius: 5px; \n padding: 10px 15px; \n cursor: pointer; \n margin-left: 47%;\n margin-top: 20px;\n}\n\n.submit-btn:hover {\n background-color: #45a049;\n}\n\n.upload-format {\n font-size: 12px;\n color: #666;\n margin: 5px 0;\n}\n\n.browse-btn {\n background-color: #4caf50;\n color: white;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n cursor: pointer;\n margin-top: 10px;\n}\n\n.browse-btn:hover {\n background-color: #45a049;\n}\n\n.document-selector {\n padding: 20px;\n margin-bottom: 20px;\n}\n\n.document-selector label {\n display: block;\n margin-bottom: 10px;\n font-weight: bold;\n color: #666;\n}\n\n.document-selector select {\n width: 100%;\n padding: 10px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 16px;\n background-color: white;\n}\n\n#selected-document-form {\n padding: 0 20px;\n overflow: auto;\n height: 65%;\n}\n\n/* Style pour l'option avec l'emoji */\n.document-selector select option {\n padding: 10px;\n font-size: 14px;\n}\n\n.members-selection {\n max-height: 200px;\n overflow-y: auto;\n border: 1px solid #ddd;\n border-radius: 4px;\n padding: 10px;\n background-color: white;\n}\n\n.member-checkbox {\n display: flex;\n align-items: center;\n margin-bottom: 8px;\n padding: 5px;\n}\n\n.member-checkbox:hover {\n background-color: #f5f5f5;\n}\n\n.member-checkbox input[type=\"checkbox\"] {\n margin-right: 10px;\n}\n\n.member-checkbox label {\n cursor: pointer;\n flex: 1;\n}\n\n/* Style pour le conteneur des membres */\n.members-selection-container {\n display: flex;\n flex-direction: column;\n align-items: center; /* Centrer la liste des membres */\n width: 100%;\n}\n\n#members-list {\n width: 60%;\n height: 100%;\n margin-bottom: -40px;\n margin-top: 10px;\n}\n\n/* Style pour le label des membres */\n.members-selection-container label {\n font-weight: bold; /* Mettre le texte en gras */\n margin-bottom: 10px; /* Espacement en bas */\n display: block; /* Affichage en bloc */\n}\n\n/* Style pour les cases à cocher des membres */\n.member-checkbox {\n display: flex;\n align-items: center;\n margin-bottom: 8px;\n padding: 5px;\n border-radius: 4px; /* Coins arrondis */\n transition: background-color 0.2s; /* Transition pour l'effet de survol */\n}\n\n.member-checkbox:hover {\n background-color: #e9ecef; /* Couleur de fond au survol */\n}\n\n/* Style pour les labels */\n.form-group label {\n font-weight: bold; \n margin-bottom: 5px; \n}\n\n/* Style pour les champs de saisie */\n.form-group input,\n.form-group select {\n padding: 10px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 16px;\n width: 80%;\n}\n\n.add-members-btn {\n background-color: #4caf50; \n color: white; \n border: none; \n border-radius: 5px; \n padding: 10px 15px; \n cursor: pointer; \n margin-top: 10px; /* Espacement au-dessus du bouton */\n}\n\n.add-members-btn:hover {\n background-color: #45a049; \n}\n\n/* Styles pour l'overlay et la modale */\n.modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.5);\n z-index: 999;\n}\n\n.modal {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 20px;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);\n z-index: 1000;\n width: 25%;\n max-width: 500px;\n}\n\n.modal-content {\n max-height: 70vh;\n overflow-y: auto;\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-end;\n gap: 10px;\n margin-top: 20px;\n padding-top: 10px;\n border-top: 1px solid #eee;\n}\n\n.confirm-btn {\n background-color: #4caf50;\n color: white;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n cursor: pointer;\n}\n\n.confirm-btn:hover {\n background-color: #45a049;\n}\n\n.selected-member {\n display: flex;\n justify-content: space-between;\n align-items: center;\n background-color: #f5f5f5;\n padding: 8px 12px;\n margin: 4px 0;\n border-radius: 4px;\n}\n\n.cancel-btn {\n background-color: #df2020; \n color: white; \n border: none;\n padding: 8px 16px; \n border-radius: 4px; \n cursor: pointer;\n}\n\n.cancel-btn:hover {\n background-color: #c62828; /\n}\n\n.remove-member-btn {\n background-color: #dc3545;\n color: white;\n border: none;\n border-radius: 50%;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n font-size: 16px;\n padding: 0;\n margin-left: 8px;\n}\n\n.remove-member-btn:hover {\n background-color: #c82333;\n}\n\n#description {\n height: 100px;\n width: 100%;\n border-radius: 20px;\n padding: 10px 0;\n padding-left: 10px;\n resize: none;\n\n}\n\n.role-item-container {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n padding: 5px 0;\n}\n\n.role-item-container span:last-child {\n margin-left: 10px;\n}\n\n.document-card .new-request-btn {\n margin-top: 60%;\n margin-left: 65%;\n padding: 6px 12px;\n background-color: #4CAF50;\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 0.9em;\n}\n\n.document-card .new-request-btn:hover {\n background-color: #45a049;\n}\n\n/* Styles pour la modale de nouveau document */\n.modal {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n justify-content: center;\n align-items: center;\n z-index: 1000;\n}\n\n\n.modal-content-document {\n background: white;\n padding: 20px;\n border-radius: 8px;\n width: 97%;\n}\n\n.modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n padding-bottom: 10px;\n border-bottom: 1px solid #eee;\n}\n\n.modal-header h2 {\n margin: 0;\n color: #333;\n}\n\n.modal-body {\n margin-bottom: 20px;\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-end;\n gap: 10px;\n padding-top: 20px;\n border-top: 1px solid #eee;\n}\n\n.modal-document {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n justify-content: center;\n align-items: center;\n z-index: 1000;\n}\n.form-group {\n margin-bottom: 15px;\n}\n\n.form-group label {\n display: block;\n margin-bottom: 5px;\n font-weight: bold;\n color: #555;\n}\n\n.form-control {\n width: 100%;\n padding: 8px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 14px;\n}\n\n.form-row {\n display: flex;\n gap: 15px;\n margin-bottom: 15px;\n}\n\n.form-group.half {\n flex: 1;\n margin-bottom: 0; /* Annule la marge du form-group standard */\n}\n\n.selected-signatories {\n margin: 10px 0;\n padding: 10px;\n border: 1px solid #ddd;\n border-radius: 4px;\n min-height: 50px;\n}\n\n.signatory-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 5px;\n margin: 5px 0;\n background: #f5f5f5;\n border-radius: 4px;\n}\n\n.remove-btn {\n background: none;\n border: none;\n color: #dc3545;\n cursor: pointer;\n font-size: 18px;\n padding: 0 5px;\n}\n\n.remove-btn:hover {\n color: #bd2130;\n}\n\n.btn-primary {\n background: #4CAF50;\n color: white;\n padding: 10px 20px;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n}\n\n.btn-primary:hover {\n background: #45a049;\n}\n\n.btn-secondary {\n background: #6c757d;\n color: white;\n padding: 8px 15px;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n}\n\n.btn-secondary:hover {\n background: #5a6268;\n}\n\n.signatories-list {\n max-height: 300px;\n overflow-y: auto;\n}\n\n.signatory-option {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px;\n border-bottom: 1px solid #eee;\n}\n\n.role-select {\n padding: 4px;\n border: 1px solid #ddd;\n border-radius: 4px;\n margin-left: auto;\n}\n\n.role-section {\n margin-bottom: 20px;\n padding: 10px;\n background: #f8f9fa;\n border-radius: 4px;\n}\n\n.role-section h4 {\n margin: 0 0 10px 0;\n color: #495057;\n}\n\n.members-selection {\n max-height: 300px;\n overflow-y: auto;\n padding: 10px;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n}\n\ninput[type=\"file\"] {\n padding: 10px;\n border: 1px dashed #ccc;\n border-radius: 4px;\n width: 100%;\n margin-top: 5px;\n}\n\n.file-upload-container {\n border: 2px dashed #ccc;\n padding: 20px;\n text-align: center;\n margin: 10px 0;\n border-radius: 5px;\n cursor: pointer;\n}\n\n.file-upload-container:hover {\n background-color: #f5f5f5;\n border-color: #666;\n}\n\n.file-upload-container.dragover {\n background-color: #f0f0f0;\n border-color: #4CAF50;\n}\n\n.file-list {\n margin-top: 10px;\n}\n\n.file-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px;\n margin: 5px 0;\n background: #f5f5f5;\n border-radius: 4px;\n}\n\n.file-info {\n display: flex;\n gap: 10px;\n align-items: center;\n}\n\n.remove-file {\n background: none;\n border: none;\n color: #ff4444;\n cursor: pointer;\n font-size: 18px;\n}\n\n#fileInput {\n display: none;\n}\n\n.required-signatories {\n margin: 10px 0;\n}\n\n.signatory-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px;\n margin: 5px 0;\n background: #f5f5f5;\n border-radius: 4px;\n}\n\n.signatory-item.locked {\n background: #e8e8e8;\n cursor: not-allowed;\n}\n\n.member-name {\n font-weight: 500;\n}\n\n.role-info {\n color: #666;\n font-size: 0.9em;\n}\n\n.lock-icon {\n margin-left: auto;\n opacity: 0.6;\n}\n\n/* Style pour la popup d'alerte */\n.alert-popup {\n position: fixed;\n top: 20px;\n left: 50%;\n transform: translateX(-50%);\n background-color: #f44336;\n color: white;\n padding: 15px 25px;\n border-radius: 4px;\n box-shadow: 0 2px 5px rgba(0,0,0,0.2);\n z-index: 1000;\n display: none;\n animation: slideDown 0.3s ease-out;\n}\n\n.sign-button {\n background-color: #4CAF50;\n color: white;\n padding: 8px 16px;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n margin-top: 10px;\n}\n\n.sign-button:hover {\n background-color: #45a049;\n}\n\n.sign-button:disabled {\n background-color: #cccccc;\n cursor: not-allowed;\n}\n\n.modal-document {\n background: white;\n border-radius: 8px;\n max-width: 800px;\n width: 90%;\n max-height: 95vh;\n overflow-y: auto;\n position: relative;\n}\n\n.document-details {\n padding: 20px;\n}\n\n.info-section {\n margin: 20px 0;\n background: #f8f9fa;\n padding: 15px;\n border-radius: 6px;\n}\n\n.info-row {\n display: flex;\n justify-content: space-between;\n margin-bottom: 10px;\n}\n\n.label {\n font-weight: bold;\n color: #666;\n}\n\n.description-section {\n margin: 20px 0;\n}\n\n.signatures-section {\n margin: 20px 0;\n}\n\n.signature-item {\n display: flex;\n justify-content: space-between;\n padding: 8px;\n border-bottom: 1px solid #eee;\n}\n\n.signature-item.signed {\n background-color: #e8f5e9;\n}\n\n.signature-item.pending {\n background-color: #fff3e0;\n}\n\n.files-section {\n margin: 20px 0;\n}\n\n.file-item {\n display: flex;\n align-items: center;\n padding: 8px;\n background: #f8f9fa;\n margin-bottom: 5px;\n border-radius: 4px;\n}\n\n.file-icon {\n margin-right: 10px;\n}\n\n.download-link {\n margin-left: auto;\n}\n\n.confirmation-section {\n margin-top: 30px;\n text-align: center;\n}\n\n.warning-text {\n color: #f44336;\n margin-bottom: 15px;\n}\n\n.sign-confirm-btn {\n background-color: #4CAF50;\n color: white;\n padding: 10px 20px;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n}\n\n.sign-confirm-btn:hover {\n background-color: #45a049;\n}\n\n.signature-slider-container {\n margin: 20px 20%;\n padding: 10px;\n}\n\n.slider-track {\n position: relative;\n background: #e0e0e0;\n height: 40px;\n border-radius: 20px;\n display: flex;\n align-items: center;\n overflow: hidden;\n}\n\n.slider-handle {\n position: absolute;\n left: 0;\n width: 40px;\n height: 40px;\n background: #4CAF50;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n touch-action: none;\n z-index: 1;\n}\n\n.slider-arrow {\n color: white;\n font-size: 20px;\n}\n\n.slider-text {\n width: 100%;\n text-align: center;\n color: #666;\n user-select: none;\n}";
// Définir les rôles autorisés
const VISIBILITY_LEVELS = {
PUBLIC: 'public',
CONFIDENTIAL: 'confidential',
PRIVATE: 'private',
};
const DOCUMENT_STATUS = {
DRAFT: 'draft',
PENDING: 'pending'};
const groupsMock = [
{
id: 1,
name: 'Processus 1',
description: 'Description du processus 1',
commonDocuments: [
{
id: 101,
name: 'Règlement intérieur',
description: 'Document vierge pour le règlement intérieur',
visibility: VISIBILITY_LEVELS.PUBLIC,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 102,
name: 'Charte de confidentialité',
description: 'Document vierge pour la charte de confidentialité',
visibility: VISIBILITY_LEVELS.CONFIDENTIAL,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 103,
name: 'Procédures générales',
description: 'Document vierge pour les procédures générales',
visibility: VISIBILITY_LEVELS.PUBLIC,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 104,
name: 'Urgency A',
description: "Document vierge pour le plan d'urgence A",
visibility: VISIBILITY_LEVELS.PRIVATE,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 105,
name: 'Urgency B',
description: "Document vierge pour le plan d'urgence B",
visibility: VISIBILITY_LEVELS.PRIVATE,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 106,
name: 'Urgency C',
description: "Document vierge pour le plan d'urgence C",
visibility: VISIBILITY_LEVELS.PRIVATE,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 107,
name: 'Document à signer',
description: 'Document vierge pour le règlement intérieur',
visibility: VISIBILITY_LEVELS.PUBLIC,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
],
roles: [
{
name: 'User',
members: [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
],
documents: [
{
id: 1,
name: 'Document User A',
description: 'Description du document User A.',
visibility: 'public',
createdAt: '2024-01-01',
deadline: '2024-02-01',
signatures: [
{
member: { id: 1, name: 'Alice' },
signed: true,
signedAt: '2024-01-15',
},
{
member: { id: 2, name: 'Bob' },
signed: false,
},
],
},
{
id: 2,
name: 'Document User B',
description: 'Document vierge pour le rôle User',
visibility: 'confidential',
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 7,
name: 'Document User C',
description: 'Document vierge pour validation utilisateur',
visibility: VISIBILITY_LEVELS.CONFIDENTIAL,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 8,
name: 'Document User D',
description: 'Document vierge pour approbation utilisateur',
visibility: VISIBILITY_LEVELS.PUBLIC,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
],
},
{
name: 'Process',
members: [
{ id: 3, name: 'Charlie' },
{ id: 4, name: 'David' },
],
documents: [
{
id: 3,
name: 'Document Process A',
description: 'Description du document Process A.',
visibility: 'confidential',
createdAt: '2024-01-10',
deadline: '2024-03-01',
signatures: [
{
member: { id: 3, name: 'Charlie' },
signed: true,
signedAt: '2024-01-12',
},
],
},
{
id: 9,
name: 'Document Process B',
description: 'Document vierge pour processus interne',
visibility: VISIBILITY_LEVELS.CONFIDENTIAL,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 10,
name: 'Document Process C',
description: 'Document vierge pour validation processus',
visibility: VISIBILITY_LEVELS.PRIVATE,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 11,
name: 'Document Process D',
description: 'Document vierge pour validation processus',
visibility: VISIBILITY_LEVELS.PUBLIC,
status: DOCUMENT_STATUS.PENDING,
createdAt: '2024-01-15',
deadline: '2024-02-01',
signatures: [
{
member: { id: 3, name: 'Charlie' },
signed: true,
signedAt: '2024-01-15',
},
{
member: { id: 4, name: 'David' },
signed: false,
},
],
},
{
id: 12,
name: 'Document Process E',
description: 'Document vierge pour validation processus',
visibility: VISIBILITY_LEVELS.PUBLIC,
status: DOCUMENT_STATUS.PENDING,
createdAt: '2024-01-15',
deadline: '2024-02-01',
signatures: [
{
member: { id: 3, name: 'Charlie' },
signed: true,
signedAt: '2024-01-15',
},
{
member: { id: 4, name: 'David' },
signed: false,
},
],
},
],
},
{
name: 'Backup',
members: [
{ id: 15, name: 'Oscar' },
{ id: 16, name: 'Patricia' },
],
documents: [
{
id: 11,
name: 'Document Backup A',
description: 'Document vierge pour sauvegarde',
visibility: VISIBILITY_LEVELS.PRIVATE,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
],
},
],
},
{
id: 2,
name: 'Processus 2',
description: 'Description du processus 2',
commonDocuments: [
{
id: 201,
name: 'Règlement intérieur',
description: 'Document vierge pour le règlement intérieur',
visibility: VISIBILITY_LEVELS.PUBLIC,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 202,
name: 'Charte de confidentialité',
description: 'Document vierge pour la charte de confidentialité',
visibility: VISIBILITY_LEVELS.CONFIDENTIAL,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 203,
name: 'Charte de confidentialité',
description: 'Document vierge pour la charte de confidentialité',
visibility: VISIBILITY_LEVELS.PRIVATE,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 204,
name: 'Charte de confidentialité',
description: 'Document vierge pour la charte de confidentialité',
visibility: VISIBILITY_LEVELS.PRIVATE,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 205,
name: 'Charte de confidentialité',
description: 'Document vierge pour la charte de confidentialité',
visibility: VISIBILITY_LEVELS.PRIVATE,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
],
roles: [
{
name: 'Artefact',
members: [
{ id: 17, name: 'Quinn' },
{ id: 18, name: 'Rachel' },
],
documents: [
{
id: 12,
name: 'Document Artefact A',
description: 'Document vierge pour artefact',
visibility: VISIBILITY_LEVELS.CONFIDENTIAL,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 13,
name: 'Document Artefact B',
description: 'Document vierge pour validation artefact',
visibility: VISIBILITY_LEVELS.PRIVATE,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
],
},
{
name: 'Resolve',
members: [
{ id: 19, name: 'Sam' },
{ id: 20, name: 'Tom' },
],
documents: [
{
id: 14,
name: 'Document Resolve A',
description: 'Document vierge pour résolution',
visibility: VISIBILITY_LEVELS.CONFIDENTIAL,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
],
},
],
},
{
id: 3,
name: 'Processus 3',
description: 'Description du processus 3',
commonDocuments: [
{
id: 301,
name: 'Règlement intérieur',
description: 'Document vierge pour le règlement intérieur',
visibility: VISIBILITY_LEVELS.PUBLIC,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 302,
name: 'Charte de confidentialité',
description: 'Document vierge pour la charte de confidentialité',
visibility: VISIBILITY_LEVELS.CONFIDENTIAL,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 303,
name: 'Procédures générales',
description: 'Document vierge pour les procédures générales',
visibility: VISIBILITY_LEVELS.PUBLIC,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
],
roles: [
{
name: 'Deposit',
members: [
{ id: 21, name: 'Uma' },
{ id: 22, name: 'Victor' },
],
documents: [
{
id: 15,
name: 'Document Deposit A',
description: 'Document vierge pour dépôt',
visibility: VISIBILITY_LEVELS.PRIVATE,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 16,
name: 'Document Deposit B',
description: 'Document vierge pour validation dépôt',
visibility: VISIBILITY_LEVELS.CONFIDENTIAL,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
],
},
{
name: 'Payment',
members: [
{ id: 23, name: 'Walter' },
{ id: 24, name: 'Xena' },
],
documents: [
{
id: 17,
name: 'Document Payment B',
description: 'Document vierge pour paiement',
visibility: VISIBILITY_LEVELS.PRIVATE,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
{
id: 18,
name: 'Document Payment C',
description: 'Document vierge pour validation paiement',
visibility: VISIBILITY_LEVELS.CONFIDENTIAL,
status: DOCUMENT_STATUS.DRAFT,
createdAt: null,
deadline: null,
signatures: [],
},
],
},
],
},
];
const messagesMock = [
{
memberId: 1,
// Conversations avec Mmber 1
messages: [
{ id: 1, sender: "Mmeber 1", text: "Salut !", time: "10:30 AM" },
{ id: 2, sender: "4NK", text: "Bonjour ! Comment ça va ?", time: "10:31 AM" },
{ id: 3, sender: "4NK", text: "Tout va bien, merci !", time: "10:32 AM" }
]
},
{
memberId: 2,
// Conversations avec Member 2
messages: [
{ id: 1, sender: "Member 2", text: "Salut, on se voit ce soir ?", time: "10:30 AM" },
{ id: 2, sender: "4NK", text: "Oui, à quelle heure ?", time: "10:31 AM" }
]
},
{
memberId: 3,
// Conversations avec Member 3
messages: [
{ id: 1, sender: "Member 3", text: "Hey, ça va ?", time: "10:30 AM" },
{ id: 2, sender: "4NK", text: "Ça va et toi ?", time: "10:31 AM" }
]
},
{
memberId: 4,
// Conversations avec Member 4
messages: [
{ id: 1, sender: "Member 4", text: "Hey, ça va ?", time: "10:30 AM" },
{ id: 2, sender: "4NK", text: "Ça va et toi ?", time: "10:31 AM" },
{ id: 3, sender: "4NK", text: "Ça va et toi ?", time: "10:31 AM" }
]
},
{
memberId: 5,
// Conversations avec Member 5
messages: [
{ id: 1, sender: "Member 5", text: "Hey, ça va ?", time: "10:30 AM" },
{ id: 2, sender: "4NK", text: "Ça va et toi ?", time: "10:31 AM" },
{ id: 3, sender: "4NK", text: "Ça va et toi ?", time: "10:31 AM" }
]
},
{
memberId: 6,
// Conversations avec Member 6
messages: [
{ id: 1, sender: "Member 6", text: "Hey, ça va ?", time: "10:30 AM" },
{ id: 2, sender: "4NK", text: "Ça va et toi ?", time: "10:31 AM" },
{ id: 3, sender: "4NK", text: "Ça va et toi ?", time: "10:31 AM" }
]
},
{
memberId: 7,
// Conversations avec Member 7
messages: [
{ id: 1, sender: "Member 7", text: "Hey, ça va ?", time: "10:30 AM" },
{ id: 2, sender: "4NK", text: "Ça va et toi ?", time: "10:31 AM" },
{ id: 3, sender: "4NK", text: "Ça va et toi ?", time: "10:31 AM" }
]
},
{
memberId: 8,
// Conversations avec Member 8
messages: [
{ id: 1, sender: "Member 8", text: "Hey, ça va ?", time: "10:30 AM" },
{ id: 2, sender: "4NK", text: "Ça va et toi ?", time: "10:31 AM" },
{ id: 3, sender: "4NK", text: "Ça va et toi ?", time: "10:31 AM" }
]
}
];
const membersMock = [
// Processus 1
{
id: 1,
name: 'Alice',
avatar: 'A',
email: 'alice@company.com',
processRoles: [{ processId: 1, role: 'User' }],
},
{
id: 2,
name: 'Bob',
avatar: 'B',
email: 'bob@company.com',
processRoles: [{ processId: 1, role: 'User' }],
},
{
id: 3,
name: 'Charlie',
avatar: 'C',
email: 'charlie@company.com',
processRoles: [{ processId: 1, role: 'Process' }],
},
{
id: 4,
name: 'David',
avatar: 'D',
email: 'david@company.com',
processRoles: [{ processId: 1, role: 'Process' }],
},
{
id: 15,
name: 'Oscar',
avatar: 'O',
email: 'oscar@company.com',
processRoles: [{ processId: 1, role: 'Backup' }],
},
{
id: 16,
name: 'Patricia',
avatar: 'P',
email: 'patricia@company.com',
processRoles: [{ processId: 1, role: 'Backup' }],
},
// Processus 2
{
id: 17,
name: 'Quinn',
avatar: 'Q',
email: 'quinn@company.com',
processRoles: [{ processId: 2, role: 'Artefact' }],
},
{
id: 18,
name: 'Rachel',
avatar: 'R',
email: 'rachel@company.com',
processRoles: [{ processId: 2, role: 'Artefact' }],
},
{
id: 19,
name: 'Sam',
avatar: 'S',
email: 'sam@company.com',
processRoles: [{ processId: 2, role: 'Resolve' }],
},
{
id: 20,
name: 'Tom',
avatar: 'T',
email: 'tom@company.com',
processRoles: [{ processId: 2, role: 'Resolve' }],
},
// Processus 3
{
id: 21,
name: 'Uma',
avatar: 'U',
email: 'uma@company.com',
processRoles: [{ processId: 3, role: 'Deposit' }],
},
{
id: 22,
name: 'Victor',
avatar: 'V',
email: 'victor@company.com',
processRoles: [{ processId: 3, role: 'Deposit' }],
},
{
id: 23,
name: 'Walter',
avatar: 'W',
email: 'walter@company.com',
processRoles: [{ processId: 3, role: 'Payment' }],
},
{
id: 24,
name: 'Xena',
avatar: 'X',
email: 'xena@company.com',
processRoles: [{ processId: 3, role: 'Payment' }],
},
];
class MessageStore {
STORAGE_KEY = "chat_messages";
messages = [];
constructor() {
this.messages = this.loadFromLocalStorage() || [];
}
loadFromLocalStorage() {
try {
const stored = localStorage.getItem(this.STORAGE_KEY);
return stored ? JSON.parse(stored) : null;
} catch (error) {
console.error("Error loading messages:", error);
return null;
}
}
getMessages() {
return this.messages;
}
setMessages(messages) {
this.messages = messages;
this.saveToLocalStorage();
}
saveToLocalStorage() {
try {
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(this.messages));
} catch (error) {
console.error("Error saving messages:", error);
}
}
addMessage(memberId, message) {
const memberMessages = this.messages.find((m) => String(m.memberId) === String(memberId));
if (memberMessages) {
memberMessages.messages.push(message);
} else {
this.messages.push({
memberId: String(memberId),
messages: [message]
});
}
this.saveToLocalStorage();
}
}
const messageStore = new MessageStore();
let currentUser = membersMock[0];
class SignatureElement extends HTMLElement {
selectedMemberId = null;
messagesMock = [];
dom;
notifications = [];
notificationBadge = document.querySelector(".notification-badge");
notificationBoard = document.getElementById("notification-board");
notificationBell = document.getElementById("notification-bell");
selectedSignatories = [];
allMembers = membersMock.map((member) => ({
id: member.id,
name: member.name,
roleName: "Default Role"
}));
showAlert(message) {
let alertPopup = this.shadowRoot?.querySelector(".alert-popup");
if (!alertPopup) {
alertPopup = document.createElement("div");
alertPopup.className = "alert-popup";
this.shadowRoot?.appendChild(alertPopup);
}
alertPopup.textContent = message;
alertPopup.style.display = "block";
setTimeout(() => {
alertPopup.style.display = "none";
}, 3e3);
}
signDocument(documentId, processId, isCommonDocument = false) {
try {
let initDrag = function(e) {
isDragging = true;
startX = "touches" in e ? e.touches[0].clientX : e.clientX;
sliderLeft = slider?.offsetLeft || 0;
}, drag = function(e) {
if (!isDragging || !slider || !sliderTrack)
return;
e.preventDefault();
const x = "touches" in e ? e.touches[0].clientX : e.clientX;
const deltaX = x - startX;
let newLeft = sliderLeft + deltaX;
const maxLeft = sliderTrack.offsetWidth - slider.offsetWidth;
newLeft = Math.max(0, Math.min(newLeft, maxLeft));
slider.style.left = `${newLeft}px`;
if (newLeft > maxLeft * 0.9) {
stopDrag(e);
this.confirmSignature(documentId, processId, isCommonDocument);
}
}, stopDrag = function(e) {
if (!isDragging || !slider)
return;
isDragging = false;
if (slider.offsetLeft < (sliderTrack?.offsetWidth || 0) * 0.9) {
slider.style.left = "0px";
}
};
if (typeof window === "undefined" || typeof document === "undefined") {
console.error("Cette fonction ne peut être exécutée que dans un navigateur");
return;
}
const groups = JSON.parse(localStorage.getItem("groups") || JSON.stringify(groupsMock));
const group = groups.find((g) => g.id === processId);
if (!group) {
throw new Error("Process not found");
}
let targetDoc;
if (isCommonDocument) {
targetDoc = group.commonDocuments.find((d) => d.id === documentId);
} else {
for (const role of group.roles) {
if (role.documents) {
targetDoc = role.documents.find((d) => d.id === documentId);
if (targetDoc)
break;
}
}
}
if (!targetDoc) {
throw new Error("Document not found");
}
const canSign = isCommonDocument ? targetDoc.signatures?.some((sig) => sig.member?.name === currentUser?.name && !sig.signed) : this.canUserSignDocument(targetDoc, currentUser?.name, currentUser);
if (!canSign) {
this.showAlert("You do not have the necessary rights to sign this document.");
return;
}
const modalHtml = `
${targetDoc.name}
Created:
${new Date(targetDoc.createdAt).toLocaleDateString()}
Deadline:
${new Date(targetDoc.deadline).toLocaleDateString()}
Visibility:
${targetDoc.visibility}
Description:
${targetDoc.description || "No description available"}
Signatures status:
${targetDoc.signatures.map((sig) => `
${sig.member.name}
${sig.signed ? `✓ Signed on ${sig.signedAt ? new Date(sig.signedAt).toLocaleDateString() : "unknown date"}` : "⌛ Pending"}
`).join("")}
${this.getFileList().length > 0 ? `
Files attached:
${this.getFileList().map((file) => `
`).join("")}
` : ""}
By signing this document, you confirm that you have read its contents.
`;
const modalElement = document.createElement("div");
modalElement.className = "modal-overlay";
modalElement.innerHTML = modalHtml;
this.shadowRoot?.appendChild(modalElement);
const slider = modalElement.querySelector("#signatureSlider");
const sliderTrack = slider?.parentElement;
let isDragging = false;
let startX;
let sliderLeft;
if (slider && sliderTrack) {
slider.addEventListener("mousedown", (e) => initDrag(e));
slider.addEventListener("touchstart", (e) => initDrag(e));
modalElement.addEventListener("mousemove", (e) => drag.call(this, e));
modalElement.addEventListener("touchmove", (e) => drag.call(this, e));
modalElement.addEventListener("mouseup", (e) => stopDrag(e));
modalElement.addEventListener("touchend", (e) => stopDrag(e));
}
} catch (error) {
console.error("Error displaying modal:", error);
this.showAlert(error instanceof Error ? error.message : "Error displaying modal");
}
}
constructor() {
super();
this.attachShadow({ mode: "open" });
this.dom = getCorrectDOM("signature-element");
this.shadowRoot.innerHTML = `
`;
window.toggleUserList = this.toggleUserList.bind(this);
window.switchUser = this.switchUser.bind(this);
window.closeProcessDetails = this.closeProcessDetails.bind(this);
window.loadMemberChat = this.loadMemberChat.bind(this);
window.closeRoleDocuments = this.closeRoleDocuments.bind(this);
window.newRequest = this.newRequest.bind(this);
window.submitRequest = this.submitRequest.bind(this);
window.closeNewRequest = this.closeNewRequest.bind(this);
window.closeModal = this.closeModal.bind(this);
window.submitNewDocument = this.submitNewDocument.bind(this);
window.submitCommonDocument = this.submitCommonDocument.bind(this);
window.signDocument = this.signDocument.bind(this);
window.confirmSignature = this.confirmSignature.bind(this);
window.submitDocumentRequest = this.submitDocumentRequest.bind(this);
document.addEventListener("click", (event) => {
if (this.notificationBoard && this.notificationBoard.style.display === "block" && !this.notificationBoard.contains(event.target) && this.notificationBell && !this.notificationBell.contains(event.target)) {
this.notificationBoard.style.display = "none";
}
});
this.initMessageEvents();
this.initFileUpload();
}
initMessageEvents() {
const sendButton = this.shadowRoot?.getElementById("send-button");
if (sendButton) {
sendButton.addEventListener("click", () => this.sendMessage());
}
const messageInput = this.shadowRoot?.getElementById("message-input");
if (messageInput) {
messageInput.addEventListener("keypress", (event) => {
if (event.key === "Enter" && !event.shiftKey) {
event.preventDefault();
this.sendMessage();
}
});
}
}
initFileUpload() {
const fileInput = this.shadowRoot?.getElementById("file-input");
if (fileInput) {
fileInput.addEventListener("change", (event) => {
const target = event.target;
if (target.files && target.files.length > 0) {
this.sendFile(target.files[0]);
}
});
}
}
calculateDuration(startDate, endDate) {
const start = new Date(startDate || "");
const end = new Date(endDate || "");
const duration = end.getTime() - start.getTime();
return Math.floor(duration / (1e3 * 60 * 60 * 24));
}
// Add this helper function
canUserAccessDocument(document2, roleId, currentUserRole) {
if (document2.visibility === "public") {
return true;
}
return roleId === currentUserRole;
}
canUserSignDocument(document2, role, user) {
console.log("Checking signing rights for:", {
document: document2,
role,
user,
userRoles: user.processRoles
});
const isSignatory = document2.signatures?.some((sig) => sig.member && "id" in sig.member && sig.member.id === user.id && !sig.signed);
if (!isSignatory) {
console.log("User is not in signatures list or has already signed");
return false;
}
return true;
}
closeProcessDetails(groupId) {
const detailsArea = this.shadowRoot?.getElementById(`process-details-${groupId}`);
const chatArea = this.shadowRoot?.getElementById("chat-area");
if (detailsArea) {
detailsArea.style.display = "none";
}
if (chatArea) {
chatArea.style.display = "block";
}
}
///////////////////// Notification module /////////////////////
// Delete a notification
removeNotification(index) {
this.notifications?.splice(index, 1);
this.renderNotifications();
this.updateNotificationBadge();
}
// Show notifications
renderNotifications() {
if (!this.notificationBoard)
return;
this.notificationBoard.innerHTML = "";
if (this.notifications.length === 0) {
this.notificationBoard.innerHTML = 'No notifications available
';
return;
}
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);
});
}
updateNotificationBadge() {
if (!this.notificationBadge)
return;
const count = this.notifications.length;
this.notificationBadge.textContent = count > 99 ? "+99" : count.toString();
this.notificationBadge.style.display = count > 0 ? "block" : "none";
}
// Add notification
addNotification(memberId, message) {
const notification = {
memberId,
text: `New message from Member ${memberId}: ${message.text}`,
time: message.time
};
this.notifications.push(notification);
this.renderNotifications();
this.updateNotificationBadge();
}
// Send a messsage
sendMessage() {
const messageInput = this.shadowRoot?.getElementById("message-input");
if (!messageInput)
return;
const messageText = messageInput.value.trim();
if (messageText === "" || this.selectedMemberId === null) {
return;
}
const newMessage = {
id: Date.now(),
sender: "4NK",
text: messageText,
time: (/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }),
type: "text"
};
messageStore.addMessage(this.selectedMemberId, newMessage);
this.messagesMock = messageStore.getMessages();
this.loadMemberChat(this.selectedMemberId);
messageInput.value = "";
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);
}
}, 2e3);
}
showProcessDetails(group, groupId) {
console.log("Showing details for group:", groupId);
const allDetailsAreas = this.shadowRoot?.querySelectorAll(".process-details");
if (allDetailsAreas) {
allDetailsAreas.forEach((area) => {
area.style.display = "none";
});
}
const container = this.shadowRoot?.querySelector(".container");
if (!container) {
console.error("Container not found");
return;
}
const storedGroups = JSON.parse(localStorage.getItem("groups") || "[]");
const storedGroup = storedGroups.find((g) => g.id === groupId);
const displayGroup = storedGroup || group;
let detailsArea = this.shadowRoot?.getElementById(`process-details-${groupId}`);
if (!detailsArea) {
detailsArea = document.createElement("div");
detailsArea.id = `process-details-${groupId}`;
detailsArea.className = "process-details";
container.appendChild(detailsArea);
}
if (detailsArea) {
detailsArea.style.display = "block";
detailsArea.innerHTML = `
Description
${displayGroup.description || "No description available"}
Documents Communs
${displayGroup.commonDocuments.map((document2) => {
const totalSignatures = document2.signatures?.length || 0;
const signedCount = document2.signatures?.filter((sig) => sig.signed).length || 0;
const percentage = totalSignatures > 0 ? signedCount / totalSignatures * 100 : 0;
const isVierge = !document2.createdAt || !document2.deadline || !document2.signatures?.length;
const canSign = document2.signatures?.some((sig) => sig.member && "id" in sig.member && sig.member.id === currentUser.id && !sig.signed);
const signButton = !isVierge ? `
${totalSignatures > 0 && signedCount < totalSignatures && canSign ? `
Sign the document
` : ""}
` : "";
return `
${!isVierge ? `
Created on: ${document2.createdAt ? new Date(document2.createdAt).toLocaleDateString() : "N/A"}
Deadline: ${document2.deadline ? new Date(document2.deadline).toLocaleDateString() : "N/A"}
Duration: ${this.calculateDuration(document2.createdAt || "", document2.deadline || "")} days
Signatures:
${document2.signatures?.map((sig) => `
${sig.member.name}
${sig.signed ? `✓ Signed on ${sig.signedAt ? new Date(sig.signedAt).toLocaleDateString() : "unknown date"}` : "⌛ Pending"}
`).join("")}
${signedCount} out of ${totalSignatures} signed (${percentage.toFixed(0)}%)
` : `
Document vierge - Waiting for creation
New request
`}
${signButton}
`;
}).join("")}
Roles and Documents
${displayGroup.roles.map((role) => {
const accessibleDocuments = (role.documents || []).filter((doc) => this.canUserAccessDocument(doc, role.name, currentUser.processRoles?.[0]?.role || ""));
return `
${role.name}
${accessibleDocuments.map((document2) => {
const isVierge = !document2.createdAt || !document2.deadline || document2.signatures.length === 0;
const canSign = this.canUserSignDocument(document2, role.name, currentUser);
const signButton = !isVierge ? `
${document2.signatures.length > 0 && document2.signatures.filter((sig) => sig.signed).length < document2.signatures.length && canSign ? `
Sign the document
` : ""}
` : "";
return `
${!isVierge ? `
Created on: ${document2.createdAt ? new Date(document2.createdAt).toLocaleDateString() : "N/A"}
Deadline: ${document2.deadline ? new Date(document2.deadline).toLocaleDateString() : "N/A"}
Duration: ${this.calculateDuration(document2.createdAt || "", document2.deadline || "")} days
` : "
Document vierge - Waiting for creation
"}
${!isVierge ? `
Signatures:
${document2.signatures.map((sig) => `
${sig.member.name}
${sig.signed ? `✓ Signé le ${sig.signedAt ? new Date(sig.signedAt).toLocaleDateString() : "date inconnue"}` : "⌛ En attente"}
`).join("")}
${document2.signatures.filter((sig) => sig.signed).length} out of ${document2.signatures.length} signed (${(document2.signatures.filter((sig) => sig.signed).length / document2.signatures.length * 100).toFixed(0)}%)
` : ""}
${signButton}
`;
}).join("")}
`;
}).join("")}
Members by Role
${displayGroup.roles.map((role) => `
${role.name}
${role.members.map((member) => `
${member.name}
`).join("")}
`).join("")}
`;
const newCloseProcessButton = document.createElement("button");
newCloseProcessButton.className = "close-btn";
newCloseProcessButton.textContent = "x";
newCloseProcessButton.addEventListener("click", () => this.closeProcessDetails(groupId));
const headerButtons = detailsArea.querySelector(".header-buttons");
if (headerButtons) {
headerButtons.appendChild(newCloseProcessButton);
}
}
}
// Scroll down the conversation after loading messages
scrollToBottom(container) {
container.scrollTop = container.scrollHeight;
}
// Load the list of members
loadMemberChat(memberId) {
this.selectedMemberId = String(memberId);
const memberMessages = this.messagesMock.find((m) => String(m.memberId) === String(memberId));
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 = this.shadowRoot?.getElementById("chat-header");
const messagesContainer = this.shadowRoot?.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) => {
const messageElement = document.createElement("div");
messageElement.className = "message-container";
const messageContent = document.createElement("div");
messageContent.className = "message";
if (message.type === "file") {
messageContent.innerHTML = `
${message.fileName} `;
messageContent.classList.add("user");
} else {
messageContent.innerHTML = `
${message.sender} : ${message.text}
${message.time} `;
if (message.sender === "4NK") {
messageContent.classList.add("user");
}
}
messageElement.appendChild(messageContent);
messagesContainer.appendChild(messageElement);
});
}
this.scrollToBottom(messagesContainer);
}
toggleMembers(role, roleElement) {
let memberList = roleElement.querySelector(".member-list");
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();
this.loadMemberChat(member.id.toString());
};
memberList.appendChild(memberItem);
});
roleElement.appendChild(memberList);
}
// Toggle the list of Roles
toggleRoles(group, groupElement) {
console.log("=== toggleRoles START ===");
console.log("Group:", group.name);
console.log("Group roles:", group.roles);
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);
let container = roleItem.querySelector(".role-item-container");
if (!container) {
container = document.createElement("div");
container.className = "role-item-container";
const nameSpan = document.createElement("span");
nameSpan.className = "role-name";
nameSpan.textContent = roleItem.textContent?.trim() || "";
container.appendChild(nameSpan);
roleItem.textContent = "";
roleItem.appendChild(container);
}
const roleName = roleItem.textContent?.trim();
console.log("Role name from textContent:", roleName);
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.innerHTML = "📁";
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);
this.showRoleDocuments(role, group);
} else {
console.error("Role not found. Name:", roleName);
console.error("Available roles:", group.roles);
}
});
container.appendChild(folderButton);
}
});
roleList.style.display = roleList.style.display === "none" ? "block" : "none";
}
}
loadGroupList() {
const groupList = this.shadowRoot?.getElementById("group-list");
if (!groupList)
return;
groupsMock.forEach((group) => {
const li = document.createElement("li");
li.className = "group-list-item";
const container = document.createElement("div");
container.className = "group-item-container";
const nameSpan = document.createElement("span");
nameSpan.textContent = group.name;
nameSpan.className = "process-name";
nameSpan.addEventListener("click", (event) => {
event.stopPropagation();
this.toggleRoles(group, li);
});
const settingsIcon = document.createElement("span");
settingsIcon.textContent = "⚙️";
settingsIcon.className = "settings-icon";
settingsIcon.id = `settings-${group.id}`;
settingsIcon.onclick = (event) => {
event.stopPropagation();
this.showProcessDetails(group, group.id);
};
container.appendChild(nameSpan);
container.appendChild(settingsIcon);
li.appendChild(container);
const roleList = document.createElement("ul");
roleList.className = "role-list";
roleList.style.display = "none";
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
toggleUserList() {
const userList = getCorrectDOM("userList");
if (!userList)
return;
if (!userList.classList.contains("show")) {
userList.innerHTML = membersMock.map((member) => `
${member.avatar}
${member.name}
${member.email}
`).join("");
}
userList.classList.toggle("show");
}
switchUser(userId) {
const user = membersMock.find((member) => member.id === userId);
if (!user)
return;
currentUser = user;
this.updateCurrentUserDisplay();
const userList = getCorrectDOM("userList");
userList?.classList.remove("show");
}
// Function to update the display of the current user
updateCurrentUserDisplay() {
const userDisplay = getCorrectDOM("current-user");
if (userDisplay) {
userDisplay.innerHTML = `
${currentUser.avatar}
${currentUser.name}
`;
}
}
// Generate an automatic response
generateAutoReply(senderName) {
return {
id: Date.now(),
sender: senderName,
text: "OK...",
time: (/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }),
type: "text"
};
}
// Send a file
sendFile(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,
fileData,
time: (/* @__PURE__ */ 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);
}
// Managing the sent file
fileList = this.shadowRoot?.getElementById("fileList");
getFileList() {
const files = Array.from(this.fileList?.querySelectorAll(".file-item") || []).map((fileItem) => {
const fileName = fileItem.querySelector(".file-name")?.textContent || "";
return {
name: fileName,
url: fileItem.dataset.content || "#"
};
});
return files;
}
// New function to display the documents of a role
showRoleDocuments(role, group) {
const storedGroups = JSON.parse(localStorage.getItem("groups") || "[]");
const storedGroup = storedGroups.find((g) => g.id === group.id);
const storedRole = storedGroup?.roles.find((r) => r.name === role.name);
const displayRole = storedRole || role;
console.log("Showing documents for role:", displayRole.name, "in group:", group.name);
const allDetailsAreas = this.shadowRoot?.querySelectorAll(".process-details");
allDetailsAreas?.forEach((area) => {
area.remove();
});
const container = this.shadowRoot?.querySelector(".container");
if (!container) {
console.error("Container not found");
return;
}
const detailsArea = document.createElement("div");
detailsArea.id = `role-documents-${displayRole.name}`;
detailsArea.className = "process-details";
const accessibleDocuments = (displayRole.documents || []).filter((doc) => this.canUserAccessDocument(doc, displayRole.name, currentUser.processRoles?.[0]?.role || ""));
detailsArea.innerHTML = `
Documents
${accessibleDocuments.map((document2) => {
const totalSignatures = document2.signatures.length;
const signedCount = document2.signatures.filter((sig) => sig.signed).length;
const percentage = totalSignatures > 0 ? signedCount / totalSignatures * 100 : 0;
const isVierge = !document2.createdAt || !document2.deadline || document2.signatures.length === 0;
this.canUserSignDocument(document2, role.name, currentUser);
return `
${!isVierge ? `
Created on: ${document2.createdAt ? new Date(document2.createdAt).toLocaleDateString() : "N/A"}
Deadline: ${document2.deadline ? new Date(document2.deadline).toLocaleDateString() : "N/A"}
Duration: ${this.calculateDuration(document2.createdAt, document2.deadline)} days
Signatures:
${document2.signatures.map((sig) => `
${sig.member.name}
${sig.signed ? `✓ Signed on ${sig.signedAt ? new Date(sig.signedAt).toLocaleDateString() : "unknown date"}` : "⌛ Pending"}
`).join("")}
${signedCount} out of ${totalSignatures} signed (${percentage.toFixed(0)}%)
` : `
Blank document - Waiting for creation
${this.canUserAccessDocument(document2, displayRole.name, currentUser.processRoles?.[0]?.role || "") ? `
New request
` : ""}
`}
`;
}).join("")}
`;
container.appendChild(detailsArea);
}
// Function to close the documents view of a role
closeRoleDocuments(roleName) {
const detailsArea = this.shadowRoot?.getElementById(`role-documents-${roleName}`);
if (detailsArea) {
detailsArea.remove();
}
}
handleFiles(files, fileList) {
Array.from(files).forEach((file) => {
const reader = new FileReader();
reader.onload = (e) => {
const fileContent = e.target?.result;
const existingFiles = fileList.querySelectorAll(".file-name");
const isDuplicate = Array.from(existingFiles).some((existingFile) => existingFile.textContent === file.name);
if (!isDuplicate) {
const fileItem = document.createElement("div");
fileItem.className = "file-item";
fileItem.innerHTML = `
${file.name}
(${(file.size / 1024).toFixed(1)} KB)
×
`;
fileItem.dataset.content = fileContent;
const removeBtn = fileItem.querySelector(".remove-file");
if (removeBtn) {
removeBtn.addEventListener("click", () => fileItem.remove());
}
fileList.appendChild(fileItem);
}
};
reader.readAsDataURL(file);
});
}
// Function to manage the new request
newRequest(params) {
if (!params || !params.processId) {
console.error("Paramètres invalides:", params);
this.showAlert("Invalid parameters for new request");
return;
}
const modal = document.createElement("div");
modal.className = "modal-overlay";
const process = groupsMock.find((g) => g.id === params.processId);
if (!process) {
console.error("Processus non trouvé:", params.processId);
this.showAlert("Process not found");
return;
}
let membersToDisplay = [];
try {
if (params.roleName === "common") {
membersToDisplay = process.roles.reduce((members, role) => {
return members.concat(role.members.map((member) => ({
...member,
roleName: role.name
})));
}, []);
} else {
const role = process.roles.find((r) => r.name === params.roleName);
if (!role) {
throw new Error(`Role ${params.roleName} not found`);
}
membersToDisplay = role.members.map((member) => ({
...member,
roleName: params.roleName
}));
}
} catch (error) {
console.error("Error retrieving members:", error);
this.showAlert("Error retrieving members");
return;
}
modal.innerHTML = `
`;
this.shadowRoot?.appendChild(modal);
const dropZone = modal.querySelector("#dropZone");
const fileInput = modal.querySelector("#fileInput");
const fileList = modal.querySelector("#fileList");
dropZone.addEventListener("click", () => {
fileInput.click();
});
fileInput.addEventListener("change", (e) => {
const target = e.target;
if (target.files && target.files.length > 0) {
this.handleFiles(target.files, fileList);
}
});
dropZone.addEventListener("dragover", (e) => {
e.preventDefault();
dropZone.classList.add("dragover");
});
dropZone.addEventListener("dragleave", () => {
dropZone.classList.remove("dragover");
});
dropZone.addEventListener("drop", (e) => {
e.preventDefault();
dropZone.classList.remove("dragover");
if (e.dataTransfer?.files) {
this.handleFiles(e.dataTransfer.files, fileList);
}
});
}
closeModal(button) {
const modalOverlay = button.closest(".modal-overlay");
if (modalOverlay) {
modalOverlay.remove();
}
}
submitNewDocument(event) {
event.preventDefault();
const form = this.shadowRoot?.getElementById("newDocumentForm");
if (!form) {
this.showAlert("Form not found");
return;
}
const fileList = this.shadowRoot?.getElementById("fileList");
const files = Array.from(fileList?.querySelectorAll(".file-item") || []).map((fileItem) => {
const fileName = fileItem.querySelector(".file-name")?.textContent || "";
return {
name: fileName,
url: fileItem.dataset.content || "#"
};
});
const processId = Number(form.querySelector("#processId")?.value);
const documentId = Number(form.querySelector("#documentId")?.value);
const documentName = form.querySelector("#documentName")?.value?.trim();
const description = form.querySelector("#description")?.value?.trim();
const deadline = form.querySelector("#deadline")?.value;
const visibility = form.querySelector("#visibility")?.value;
if (!documentName || !description || !deadline) {
this.showAlert("Please fill in all required fields");
return;
}
try {
const groups = JSON.parse(localStorage.getItem("groups") || JSON.stringify(groupsMock));
const group = groups.find((g) => g.id === processId);
if (!group) {
this.showAlert("Process not found");
return;
}
const role = group.roles.find((r) => r.documents?.some((d) => d.id === documentId));
if (!role) {
this.showAlert("Role not found");
return;
}
const updatedDocument = {
id: documentId,
name: documentName,
description,
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
deadline,
visibility,
status: "pending",
signatures: role.members.map((member) => ({
member,
signed: false,
signedAt: null
})),
files
// Ajout des fichiers au document
};
const documentIndex = role.documents.findIndex((d) => d.id === documentId);
if (documentIndex !== -1) {
role.documents[documentIndex] = updatedDocument;
}
localStorage.setItem("groups", JSON.stringify(groups));
const mockGroup = groupsMock.find((g) => g.id === processId);
if (mockGroup) {
const mockRole = mockGroup?.roles.find((r) => r.name === role.name);
if (mockRole?.documents) {
const mockDocIndex = mockRole.documents.findIndex((d) => d.id === documentId);
if (mockDocIndex !== -1) {
mockRole.documents[mockDocIndex] = {
...updatedDocument,
status: void 0
};
}
}
}
if (event.target instanceof HTMLElement) {
this.closeModal(event.target);
}
this.showRoleDocuments(role, group);
this.showAlert("Document updated successfully!");
} catch (error) {
console.error("Error saving:", error);
this.showAlert("An error occurred while saving");
}
}
submitCommonDocument(event) {
event.preventDefault();
const form = this.shadowRoot?.getElementById("newDocumentForm");
if (!form) {
this.showAlert("Form not found");
return;
}
const processId = Number(form.querySelector("#processId")?.value);
const documentId = Number(form.querySelector("#documentId")?.value);
const documentName = form.querySelector("#documentName")?.value?.trim();
const description = form.querySelector("#description")?.value?.trim();
const deadline = form.querySelector("#deadline")?.value;
const visibility = form.querySelector("#visibility")?.value;
if (!documentName || !description || !deadline) {
this.showAlert("Please fill in all required fields");
return;
}
try {
const groups = JSON.parse(localStorage.getItem("groups") || JSON.stringify(groupsMock));
const group = groups.find((g) => g.id === processId);
if (!group) {
this.showAlert("Process not found");
return;
}
const allMembers = group.roles.reduce((acc, role) => {
return acc.concat(role.members);
}, []);
const fileList = this.shadowRoot?.getElementById("fileList");
const files = Array.from(fileList?.querySelectorAll(".file-item") || []).map((fileItem) => {
const fileName = fileItem.querySelector(".file-name")?.textContent || "";
return {
name: fileName,
url: fileItem.dataset.content || "#"
};
});
const updatedDocument = {
id: documentId,
name: documentName,
description,
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
deadline,
visibility,
status: "pending",
signatures: allMembers.map((member) => ({
member,
signed: false,
signedAt: null
})),
files
};
const documentIndex = group.commonDocuments.findIndex((d) => d.id === documentId);
if (documentIndex !== -1) {
group.commonDocuments[documentIndex] = updatedDocument;
}
localStorage.setItem("groups", JSON.stringify(groups));
if (event.target instanceof HTMLElement) {
this.closeModal(event.target);
}
this.showProcessDetails(group, group.id);
this.showAlert("Document common updated successfully!");
} catch (error) {
console.error("Error saving:", error);
this.showAlert("An error occurred while saving");
}
}
submitRequest() {
this.showAlert("Request submitted!");
}
closeNewRequest() {
const newRequestView = document.getElementById("new-request-view");
if (newRequestView) {
newRequestView.style.display = "none";
newRequestView.remove();
}
}
submitDocumentRequest(documentId) {
const createdAt = this.shadowRoot?.getElementById("createdAt")?.value || "";
const deadline = this.shadowRoot?.getElementById("deadline")?.value || "";
const visibility = this.shadowRoot?.getElementById("visibility")?.value || "";
const description = this.shadowRoot?.getElementById("description")?.value || "";
const selectedMembers = Array.from(this.shadowRoot?.querySelectorAll('input[name="selected-members"]:checked') || []).map((checkbox) => checkbox.value);
if (!createdAt || !deadline || selectedMembers.length === 0) {
this.showAlert("Please fill in all required fields and select at least one member.");
return;
}
console.log("Document submission:", {
documentId,
createdAt,
deadline,
visibility,
description,
selectedMembers
});
this.showAlert("Document request submitted successfully!");
this.closeNewRequest();
}
// FUNCTIONS FOR SIGNATURE
// New function to confirm the signature
confirmSignature(documentId, processId, isCommonDocument) {
try {
console.log("Current user:", currentUser);
const groups = JSON.parse(localStorage.getItem("groups") || JSON.stringify(groupsMock));
const group = groups.find((g) => g.id === processId);
if (!group) {
throw new Error("Process not found");
}
let targetDoc;
if (isCommonDocument) {
targetDoc = group.commonDocuments.find((d) => d.id === documentId);
} else {
for (const role of group.roles) {
if (role.documents) {
targetDoc = role.documents.find((d) => d.id === documentId);
if (targetDoc)
break;
}
}
}
if (!targetDoc) {
throw new Error("Document not found");
}
const userSignature = targetDoc.signatures.find((sig) => sig.member.name === currentUser.name);
if (!userSignature) {
throw new Error(`The user ${currentUser.name} is not authorized to sign this document. Please log in with an authorized user.`);
}
userSignature.signed = true;
userSignature.signedAt = (/* @__PURE__ */ new Date()).toISOString();
localStorage.setItem("groups", JSON.stringify(groups));
const modalOverlay = this.shadowRoot?.querySelector(".modal-overlay");
if (modalOverlay) {
modalOverlay.remove();
}
if (isCommonDocument) {
this.showProcessDetails(group, processId);
} else {
const role = group.roles.find((r) => r.documents?.includes(targetDoc));
if (role) {
this.showRoleDocuments(role, group);
}
}
this.showAlert("Document signed successfully!");
} catch (error) {
console.error("Error signing document:", error);
this.showAlert(error instanceof Error ? error.message : "Error signing document");
}
}
initializeEventListeners() {
document.addEventListener("DOMContentLoaded", () => {
const newRequestBtn = this.shadowRoot?.getElementById("newRequestBtn");
if (newRequestBtn) {
newRequestBtn.addEventListener("click", () => {
this.newRequest({
processId: 0,
processName: "",
roleId: 0,
roleName: "",
documentId: 0,
documentName: ""
});
});
}
});
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) => {
if (event.key === "Enter") {
event.preventDefault();
this.sendMessage();
}
});
}
const fileInput = this.shadowRoot?.querySelector("#file-input");
if (fileInput) {
fileInput.addEventListener("change", (event) => {
const file = event.target.files?.[0];
if (file) {
this.sendFile(file);
}
});
}
}
connectedCallback() {
this.messagesMock = messageStore.getMessages();
if (this.messagesMock.length === 0) {
messageStore.setMessages(messagesMock);
this.messagesMock = messageStore.getMessages();
}
this.updateCurrentUserDisplay();
this.initializeEventListeners();
this.loadGroupList();
}
}
customElements.define("signature-element", SignatureElement);
const signatureCss = "/* Styles de base */\n:root {\n --primary-color: #3A506B;\n /* Bleu métallique */\n --secondary-color: #B0BEC5;\n /* Gris acier */\n --accent-color: #D68C45;\n /* Cuivre */\n}\n\nbody {\n font-family: Arial, sans-serif;\n margin: 0;\n padding: 0;\n display: flex;\n height: 100vh;\n background-color: #e9edf1;\n flex-direction: column;\n}\n\n\n\n/* 4NK NAVBAR */\n\n.brand-logo {\n text-align: center;\n font-size: 1.5em;\n font-weight: bold;\n}\n\n.nav-wrapper {\n position: fixed;\n background: radial-gradient(circle, white, var(--primary-color));\n display: flex;\n justify-content: space-between;\n align-items: center;\n color: #37474F;\n height: 9vh;\n width: 100vw;\n left: 0;\n top: 0;\n box-shadow: 0px 8px 10px -5px rgba(0, 0, 0, .2), 0px 16px 24px 2px rgba(0, 0, 0, .14), 0px 6px 30px 5px rgba(0, 0, 0, .12);\n}\n\n/* Icônes de la barre de navigation */\n.nav-right-icons {\n display: flex;\n}\n\n.notification-bell,\n.burger-menu {\n height: 20px;\n width: 20px;\n margin-right: 1rem;\n cursor: pointer;\n}\n\n.notification-container {\n position: relative;\n /* Conserve la position pour le notification-board */\n display: inline-flex;\n align-items: center;\n}\n\n.notification-board {\n position: absolute;\n /* Position absolue pour le placer par rapport au container */\n top: 40px;\n right: 0;\n background-color: white;\n border: 1px solid #ccc;\n padding: 10px;\n width: 200px;\n max-height: 300px;\n overflow-y: auto;\n /* Scroll si les notifications dépassent la taille */\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n z-index: 10;\n /* Définit la priorité d'affichage au-dessus des autres éléments */\n display: none;\n /* Par défaut, la notification est masquée */\n}\n\n.notification-item{\n cursor: pointer;\n}\n\n.notification-badge {\n position: absolute;\n top: -18px;\n right: 35px;\n background-color: red;\n color: white;\n border-radius: 50%;\n padding: 4px 8px;\n font-size: 12px;\n display: none;\n /* S'affiche seulement lorsqu'il y a des notifications */\n z-index: 10;\n}\n\n/* Par défaut, le menu est masqué */\n#menu {\n display: none;\n /* Menu caché par défaut */\n transition: display 0.3s ease-in-out;\n}\n\n.burger-menu {\n cursor: pointer;\n}\n\n/* Icône burger */\n#burger-icon {\n cursor: pointer;\n}\n\n.menu-content {\n display: none;\n position: absolute;\n top: 3.4rem;\n right: 1rem;\n background-color: white;\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n border-radius: 5px;\n overflow: hidden;\n}\n\n.menu-content a {\n display: block;\n padding: 10px 20px;\n text-decoration: none;\n color: #333;\n border-bottom: 1px solid #e0e0e0;\n\n &:hover {\n background-color: rgba(26, 28, 24, .08);\n }\n}\n\n.menu-content a:last-child {\n border-bottom: none;\n}\n\n/* Ajustement pour la barre de navigation fixe */\n.container {\n display: flex;\n flex: 1;\n height: 90vh;\n margin-top: 9vh;\n margin-left: -1%;\n text-align: left;\n width: 209vh;\n}\n\n\n/* Liste des groupes */\n\n.group-list {\n width: 25%;\n background-color: #1f2c3d;\n color: white;\n padding: 20px;\n box-sizing: border-box;\n overflow-y: auto;\n border-right: 2px solid #2c3e50;\n flex-shrink: 0;\n padding-right: 10px;\n height: 91vh;\n}\n\n.group-list ul {\n cursor: pointer;\n list-style: none;\n padding: 0;\n padding-right: 10px;\n margin-left: 20px;\n}\n\n.group-list li {\n margin-bottom: 10px;\n padding: 15px;\n border-radius: 8px;\n background-color: #273646;\n cursor: pointer;\n transition: background-color 0.3s, box-shadow 0.3s;\n}\n\n.group-list li:hover {\n background-color: #34495e;\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);\n}\n\n\n/* Zone de chat */\n\n.chat-area {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-width: 0;\n background-color: #ffffff;\n border-radius: 10px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);\n margin: 0px;\n margin-top: 20px;\n margin-left: 1%;\n margin-bottom: -7px;\n}\n\n/* En-tête du chat */\n.chat-header {\n background-color: #34495e;\n color: white;\n padding: 15px;\n font-size: 20px;\n font-weight: bold;\n border-radius: 10px 10px 0 0;\n text-align: center;\n}\n\n/* Messages */\n.messages {\n flex: 1;\n padding: 20px;\n overflow-y: auto;\n background-color: #f1f1f1;\n border-top: 1px solid #ddd;\n}\n\n.message-container {\n max-width: 100%;\n border-radius: 5px;\n overflow-wrap: break-word;\n word-wrap: break-word;\n background-color: #f1f1f1;\n display: flex; \n flex-direction: column; \n}\n\n.message-container .message {\n align-self: flex-start; \n}\n\n.message-container .message.user {\n align-self: flex-end; \n margin-left: auto; \n color: white;\n}\n\n.message {\n padding: 12px 18px;\n background-color: #e1e1e1;\n border-radius: 15px;\n max-width: 70%;\n font-size: 16px;\n line-height: 1.4;\n margin-bottom: 0%;\n white-space: pre-wrap;\n word-wrap: break-word;\n position: relative;\n display: inline-block;\n}\n\n/* Messages de l'utilisateur */\n.message.user {\n background-color: #3498db;\n color: white;\n align-self: flex-end;\n text-align: right;\n}\n\n/* Amélioration de l'esthétique des messages */\n/* .message.user:before {\n content: '';\n position: absolute;\n top: 10px;\n right: -10px;\n border: 10px solid transparent;\n border-left-color: #3498db;\n} */\n\n/* Zone de saisie */\n.input-area {\n padding: 10px;\n background-color: #bdc3c7;\n display: flex;\n align-items: center;\n /* Alignement vertical */\n}\n\n.input-area input[type=\"text\"] {\n flex: 1;\n /* Prend l'espace restant */\n padding: 10px;\n border: 1px solid #ccc;\n border-radius: 5px;\n}\n\n.input-area .attachment-icon {\n margin: 0 10px;\n cursor: pointer;\n display: flex;\n align-items: center;\n}\n\n.input-area button {\n padding: 10px;\n margin-left: 10px;\n background-color: #2980b9;\n color: white;\n border: none;\n border-radius: 5px;\n cursor: pointer;\n}\n\n.input-area button:hover {\n background-color: #1f608d;\n}\n\n#message-input {\n width: 100%;\n height: 50px;\n resize: none;\n padding: 10px;\n box-sizing: border-box;\n overflow: auto;\n max-width: 100%;\n border-radius: 10px;\n}\n\n/* Responsive */\n@media screen and (max-width: 768px) {\n .group-list {\n display: none;\n /* Masquer la liste des groupes sur les petits écrans */\n }\n\n .chat-area {\n margin: 0;\n }\n}\n\n#process-details {\n flex: 1;\n background: white;\n border-radius: 8px;\n margin: 10px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n display: none;\n overflow: hidden;\n}\n\n.process-details-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 20px;\n background: #f8f9fa;\n border-bottom: 1px solid #eee;\n border-radius: 8px 8px 0 0;\n}\n\n.process-details-header h2 {\n margin: 0;\n color: #333;\n}\n\n.close-btn {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #666;\n}\n\n.close-btn:hover {\n color: #333;\n}\n\n.process-details-content {\n padding: 20px;\n overflow-y: auto;\n height: calc(100% - 70px);\n}\n\n.details-section {\n margin-bottom: 30px;\n}\n\n.details-section h3 {\n color: #444;\n margin-bottom: 15px;\n padding-bottom: 8px;\n border-bottom: 2px solid #f0f0f0;\n}\n\n.documents-list {\n list-style: none;\n padding: 0;\n}\n\n.documents-list li {\n padding: 8px 0;\n border-bottom: 1px solid #eee;\n}\n\n.roles-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));\n gap: 20px;\n}\n\n.role-block {\n background: #f8f9fa;\n border-radius: 8px;\n padding: 15px;\n border: 1px solid #eee;\n}\n\n.role-block h4 {\n color: #555;\n margin: 0 0 10px 0;\n padding-bottom: 8px;\n border-bottom: 1px solid #eee;\n}\n\n.members-list {\n list-style: none;\n padding: 0;\n}\n\n.members-list li {\n padding: 8px 12px;\n margin: 4px 0;\n cursor: pointer;\n border-radius: 4px;\n transition: background-color 0.2s;\n}\n\n.members-list li:hover {\n background-color: #e9ecef;\n}\n\n.group-list-item {\n padding: 8px 16px;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n\n.group-item-container {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n}\n\n.process-name {\n flex-grow: 1;\n cursor: pointer;\n}\n\n.settings-icon {\n cursor: pointer;\n padding: 5px 8px;\n margin-left: 10px;\n border-radius: 4px;\n}\n\n.settings-icon:hover {\n background-color: rgba(255, 255, 255, 0.1);\n}\n\n.process-details {\n position: fixed;\n top: 9vh;\n right: 0;\n bottom: 0;\n left: 23.5%;\n background-color: white;\n box-sizing: border-box;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n border-radius: 8px;\n margin: 10px;\n z-index: 990;\n}\n\n.process-details-content {\n height: calc(100% - 60px); /* Ajusté pour tenir compte du header */\n overflow-y: auto;\n padding: 20px;\n}\n\n.documents-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 20px;\n margin-top: 15px;\n}\n\n.document-card {\n background: white;\n border-radius: 8px;\n padding: 15px;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n border: 1px solid #eee;\n}\n\n.document-card.public {\n border-left: 4px solid #4CAF50;\n}\n\n.document-card.private {\n border-left: 4px solid #FFC107;\n}\n\n.document-card.confidential {\n border-left: 4px solid #F44336;\n}\n\n.document-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 10px;\n padding-bottom: 10px;\n border-bottom: 1px solid #eee;\n}\n\n.document-header h4 {\n margin: 0;\n color: #333;\n}\n\n.document-visibility {\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 12px;\n font-weight: bold;\n}\n\n.public .document-visibility {\n background-color: #E8F5E9;\n color: #2E7D32;\n}\n\n.private .document-visibility {\n background-color: #FFF3E0;\n color: #F57C00;\n}\n\n.confidential .document-visibility {\n background-color: #FFEBEE;\n color: #C62828;\n}\n\n.document-info {\n margin: 10px 0;\n font-size: 14px;\n color: #666;\n}\n\n.document-info p {\n margin: 5px 0;\n}\n\n.signatures-list {\n margin-top: 10px;\n}\n\n.signature-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px;\n border-radius: 4px;\n margin: 5px 0;\n background-color: #f8f9fa;\n}\n\n.signature-item.signed {\n background-color: #E8F5E9;\n}\n\n.signature-item.pending {\n background-color: #FFF3E0;\n}\n\n.signer-name {\n font-weight: 500;\n}\n\n.signature-status {\n font-size: 12px;\n}\n\n.signed .signature-status {\n color: #2E7D32;\n}\n\n.pending .signature-status {\n color: #F57C00;\n}\n\n.user-selector {\n position: relative;\n margin-right: 20px;\n}\n\n#userSwitchBtn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 8px 12px;\n border-radius: 4px;\n display: flex;\n align-items: center;\n color: var(--primary-color);\n}\n\n#userSwitchBtn:hover {\n background-color: rgba(0, 0, 0, 0.05);\n}\n\n.current-user-info {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.user-avatar {\n background-color: var(--primary-color);\n color: white;\n width: 32px;\n height: 32px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-weight: bold;\n}\n\n.user-list {\n position: absolute;\n top: 100%;\n right: 0;\n background: white;\n border-radius: 4px;\n box-shadow: 0 2px 10px rgba(0,0,0,0.1);\n display: none;\n z-index: 1000;\n max-height: 400px;\n overflow-y: auto;\n width: 250px;\n}\n\n.user-list.show {\n display: block;\n}\n\n.user-list-item {\n padding: 8px 16px;\n display: flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n}\n\n.user-list-item:hover {\n background-color: rgba(0, 0, 0, 0.05);\n}\n\n.user-list-item .user-avatar {\n width: 24px;\n height: 24px;\n font-size: 12px;\n}\n\n.user-list-item .user-email {\n font-size: 12px;\n color: #666;\n display: block;\n}\n\n.document-card {\n margin-bottom: 20px;\n padding: 10px;\n border: 1px solid #ccc;\n border-radius: 5px;\n}\n\n.progress-bar {\n background-color: #f3f3f3;\n border-radius: 5px;\n height: 10px;\n width: 100%;\n margin-top: 5px;\n}\n\n.progress {\n background-color: #4caf50; /* Couleur de la barre de progression */\n height: 100%;\n border-radius: 5px;\n}\n\n.new-request-btn {\n background-color: #4caf50; \n color: white; \n border: none;\n border-radius: 5px; \n padding: 10px 15px; \n cursor: pointer; \n margin-left: 10px;\n}\n\n.new-request-btn:hover {\n background-color: #45a049; \n}\n\n.header-buttons {\n display: flex;\n align-items: center; \n gap: 10px; \n}\n\n.close-btn {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #666;\n}\n\n.close-btn:hover {\n color: #333;\n}\n\n.new-request-view {\n padding: 20px;\n background-color: white;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n margin: 20px;\n}\n\n.upload-area {\n border: 2px dashed #ccc;\n padding: 20px;\n text-align: center;\n margin: 20px 0;\n}\n\n.upload-icon {\n font-size: 50px;\n margin: 10px 0;\n}\n\n/* New Request View */\n.new-request-view {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: white;\n z-index: 1000; \n padding: 20px;\n box-sizing: border-box;\n overflow-y: auto;\n}\n\n.upload-area {\n border: 2px dashed #ccc;\n padding: 40px;\n text-align: center;\n margin: 20px auto;\n max-width: 600px;\n background-color: #f9f9f9;\n border-radius: 8px;\n cursor: pointer;\n}\n\n.upload-icon {\n font-size: 50px;\n margin: 20px 0;\n}\n\n.new-request-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-top: 60px;\n padding: 0 20px;\n}\n\n.upload-area {\n border: 2px dashed #ccc;\n padding: 40px;\n text-align: center;\n margin: 20px auto;\n max-width: 600px;\n background-color: #f9f9f9;\n border-radius: 8px;\n cursor: pointer;\n}\n\n.details-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n background-color: #f8f9fa;\n padding: 5px 20px;\n border-radius:20px;\n}\n\n.header-buttons {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-direction: row; \n}\n\n.close-btn {\n background: none;\n border: none;\n font-size: 24px;\n cursor: pointer;\n color: #666;\n padding: 5px;\n}\n\n.close-btn:hover {\n color: #333;\n}\n\n.new-request-btn {\n background-color: #4caf50;\n color: white;\n border: none;\n border-radius: 5px;\n padding: 8px 16px;\n cursor: pointer;\n /* margin-left: 10px; <- Supprimez cette ligne si elle existe */\n}\n\n.new-request-btn:hover {\n background-color: #45a049;\n}\n\n/* Ajoutez ces styles à votre fichier CSS existant */\n.document-card.vierge {\n background-color: #fff3cd;\n border: 2px solid #ffeeba;\n}\n\n.document-card.vierge .document-header {\n background-color: #fff3cd;\n}\n\n.document-card.vierge h4 {\n color: #856404;\n}\n\n.document-card.vierge .document-info {\n color: #856404;\n}\n\n/* Style pour l'emoji d'avertissement */\n.document-card.vierge h4::before {\n margin-right: 8px;\n}\n\n.vierge-documents-container {\n padding: 20px;\n overflow-y: auto;\n max-height: calc(100vh - 150px);\n}\n\n.document-form {\n padding: 15px;\n background-color: #fff;\n border-radius: 0 0 5px 5px;\n display: flex;\n gap: 20px;\n}\n\n.form-left {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 15px;\n}\n\n.form-right {\n display: flex;\n flex-direction: column;\n align-items: flex-end; /* Aligner le bouton à droite */\n}\n\n.form-group {\n flex: 2;\n display: flex;\n flex-direction: column;\n margin-bottom: 15px;\n}\n\n.form-group-members {\n flex: 2;\n display: flex;\n flex-direction: column;\n margin-bottom: 15px;\n font-weight: bold;\n}\n\n.submit-btn {\n background-color: #4caf50; \n color: white; \n border: none;\n border-radius: 5px; \n padding: 10px 15px; \n cursor: pointer; \n margin-left: 47%;\n margin-top: 20px;\n}\n\n.submit-btn:hover {\n background-color: #45a049;\n}\n\n.upload-format {\n font-size: 12px;\n color: #666;\n margin: 5px 0;\n}\n\n.browse-btn {\n background-color: #4caf50;\n color: white;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n cursor: pointer;\n margin-top: 10px;\n}\n\n.browse-btn:hover {\n background-color: #45a049;\n}\n\n.document-selector {\n padding: 20px;\n margin-bottom: 20px;\n}\n\n.document-selector label {\n display: block;\n margin-bottom: 10px;\n font-weight: bold;\n color: #666;\n}\n\n.document-selector select {\n width: 100%;\n padding: 10px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 16px;\n background-color: white;\n}\n\n#selected-document-form {\n padding: 0 20px;\n overflow: auto;\n height: 65%;\n}\n\n/* Style pour l'option avec l'emoji */\n.document-selector select option {\n padding: 10px;\n font-size: 14px;\n}\n\n.members-selection {\n max-height: 200px;\n overflow-y: auto;\n border: 1px solid #ddd;\n border-radius: 4px;\n padding: 10px;\n background-color: white;\n}\n\n.member-checkbox {\n display: flex;\n align-items: center;\n margin-bottom: 8px;\n padding: 5px;\n}\n\n.member-checkbox:hover {\n background-color: #f5f5f5;\n}\n\n.member-checkbox input[type=\"checkbox\"] {\n margin-right: 10px;\n}\n\n.member-checkbox label {\n cursor: pointer;\n flex: 1;\n}\n\n/* Style pour le conteneur des membres */\n.members-selection-container {\n display: flex;\n flex-direction: column;\n align-items: center; /* Centrer la liste des membres */\n width: 100%;\n}\n\n#members-list {\n width: 60%;\n height: 100%;\n margin-bottom: -40px;\n margin-top: 10px;\n}\n\n/* Style pour le label des membres */\n.members-selection-container label {\n font-weight: bold; /* Mettre le texte en gras */\n margin-bottom: 10px; /* Espacement en bas */\n display: block; /* Affichage en bloc */\n}\n\n/* Style pour les cases à cocher des membres */\n.member-checkbox {\n display: flex;\n align-items: center;\n margin-bottom: 8px;\n padding: 5px;\n border-radius: 4px; /* Coins arrondis */\n transition: background-color 0.2s; /* Transition pour l'effet de survol */\n}\n\n.member-checkbox:hover {\n background-color: #e9ecef; /* Couleur de fond au survol */\n}\n\n/* Style pour les labels */\n.form-group label {\n font-weight: bold; \n margin-bottom: 5px; \n}\n\n/* Style pour les champs de saisie */\n.form-group input,\n.form-group select {\n padding: 10px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 16px;\n width: 80%;\n}\n\n.add-members-btn {\n background-color: #4caf50; \n color: white; \n border: none; \n border-radius: 5px; \n padding: 10px 15px; \n cursor: pointer; \n margin-top: 10px; /* Espacement au-dessus du bouton */\n}\n\n.add-members-btn:hover {\n background-color: #45a049; \n}\n\n/* Styles pour l'overlay et la modale */\n.modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.5);\n z-index: 999;\n}\n\n.modal {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: white;\n padding: 20px;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);\n z-index: 1000;\n width: 25%;\n max-width: 500px;\n}\n\n.modal-content {\n max-height: 70vh;\n overflow-y: auto;\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-end;\n gap: 10px;\n margin-top: 20px;\n padding-top: 10px;\n border-top: 1px solid #eee;\n}\n\n.confirm-btn {\n background-color: #4caf50;\n color: white;\n border: none;\n padding: 8px 16px;\n border-radius: 4px;\n cursor: pointer;\n}\n\n.confirm-btn:hover {\n background-color: #45a049;\n}\n\n.selected-member {\n display: flex;\n justify-content: space-between;\n align-items: center;\n background-color: #f5f5f5;\n padding: 8px 12px;\n margin: 4px 0;\n border-radius: 4px;\n}\n\n.cancel-btn {\n background-color: #df2020; \n color: white; \n border: none;\n padding: 8px 16px; \n border-radius: 4px; \n cursor: pointer;\n}\n\n.cancel-btn:hover {\n background-color: #c62828; /\n}\n\n.remove-member-btn {\n background-color: #dc3545;\n color: white;\n border: none;\n border-radius: 50%;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n font-size: 16px;\n padding: 0;\n margin-left: 8px;\n}\n\n.remove-member-btn:hover {\n background-color: #c82333;\n}\n\n#description {\n height: 100px;\n width: 100%;\n border-radius: 20px;\n padding: 10px 0;\n padding-left: 10px;\n resize: none;\n\n}\n\n.role-item-container {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n padding: 5px 0;\n}\n\n.role-item-container span:last-child {\n margin-left: 10px;\n}\n\n.document-card .new-request-btn {\n margin-top: 60%;\n margin-left: 65%;\n padding: 6px 12px;\n background-color: #4CAF50;\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 0.9em;\n}\n\n.document-card .new-request-btn:hover {\n background-color: #45a049;\n}\n\n/* Styles pour la modale de nouveau document */\n.modal {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n justify-content: center;\n align-items: center;\n z-index: 1000;\n}\n\n\n.modal-content-document {\n background: white;\n padding: 20px;\n border-radius: 8px;\n width: 97%;\n}\n\n.modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n padding-bottom: 10px;\n border-bottom: 1px solid #eee;\n}\n\n.modal-header h2 {\n margin: 0;\n color: #333;\n}\n\n.modal-body {\n margin-bottom: 20px;\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-end;\n gap: 10px;\n padding-top: 20px;\n border-top: 1px solid #eee;\n}\n\n.modal-document {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n justify-content: center;\n align-items: center;\n z-index: 1000;\n}\n.form-group {\n margin-bottom: 15px;\n}\n\n.form-group label {\n display: block;\n margin-bottom: 5px;\n font-weight: bold;\n color: #555;\n}\n\n.form-control {\n width: 100%;\n padding: 8px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 14px;\n}\n\n.form-row {\n display: flex;\n gap: 15px;\n margin-bottom: 15px;\n}\n\n.form-group.half {\n flex: 1;\n margin-bottom: 0; /* Annule la marge du form-group standard */\n}\n\n.selected-signatories {\n margin: 10px 0;\n padding: 10px;\n border: 1px solid #ddd;\n border-radius: 4px;\n min-height: 50px;\n}\n\n.signatory-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 5px;\n margin: 5px 0;\n background: #f5f5f5;\n border-radius: 4px;\n}\n\n.remove-btn {\n background: none;\n border: none;\n color: #dc3545;\n cursor: pointer;\n font-size: 18px;\n padding: 0 5px;\n}\n\n.remove-btn:hover {\n color: #bd2130;\n}\n\n.btn-primary {\n background: #4CAF50;\n color: white;\n padding: 10px 20px;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n}\n\n.btn-primary:hover {\n background: #45a049;\n}\n\n.btn-secondary {\n background: #6c757d;\n color: white;\n padding: 8px 15px;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n}\n\n.btn-secondary:hover {\n background: #5a6268;\n}\n\n.signatories-list {\n max-height: 300px;\n overflow-y: auto;\n}\n\n.signatory-option {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px;\n border-bottom: 1px solid #eee;\n}\n\n.role-select {\n padding: 4px;\n border: 1px solid #ddd;\n border-radius: 4px;\n margin-left: auto;\n}\n\n.role-section {\n margin-bottom: 20px;\n padding: 10px;\n background: #f8f9fa;\n border-radius: 4px;\n}\n\n.role-section h4 {\n margin: 0 0 10px 0;\n color: #495057;\n}\n\n.members-selection {\n max-height: 300px;\n overflow-y: auto;\n padding: 10px;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n}\n\ninput[type=\"file\"] {\n padding: 10px;\n border: 1px dashed #ccc;\n border-radius: 4px;\n width: 100%;\n margin-top: 5px;\n}\n\n.file-upload-container {\n border: 2px dashed #ccc;\n padding: 20px;\n text-align: center;\n margin: 10px 0;\n border-radius: 5px;\n cursor: pointer;\n}\n\n.file-upload-container:hover {\n background-color: #f5f5f5;\n border-color: #666;\n}\n\n.file-upload-container.dragover {\n background-color: #f0f0f0;\n border-color: #4CAF50;\n}\n\n.file-list {\n margin-top: 10px;\n}\n\n.file-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px;\n margin: 5px 0;\n background: #f5f5f5;\n border-radius: 4px;\n}\n\n.file-info {\n display: flex;\n gap: 10px;\n align-items: center;\n}\n\n.remove-file {\n background: none;\n border: none;\n color: #ff4444;\n cursor: pointer;\n font-size: 18px;\n}\n\n#fileInput {\n display: none;\n}\n\n.required-signatories {\n margin: 10px 0;\n}\n\n.signatory-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px;\n margin: 5px 0;\n background: #f5f5f5;\n border-radius: 4px;\n}\n\n.signatory-item.locked {\n background: #e8e8e8;\n cursor: not-allowed;\n}\n\n.member-name {\n font-weight: 500;\n}\n\n.role-info {\n color: #666;\n font-size: 0.9em;\n}\n\n.lock-icon {\n margin-left: auto;\n opacity: 0.6;\n}\n\n/* Style pour la popup d'alerte */\n.alert-popup {\n position: fixed;\n top: 20px;\n left: 50%;\n transform: translateX(-50%);\n background-color: #f44336;\n color: white;\n padding: 15px 25px;\n border-radius: 4px;\n box-shadow: 0 2px 5px rgba(0,0,0,0.2);\n z-index: 1000;\n display: none;\n animation: slideDown 0.3s ease-out;\n}\n\n.sign-button {\n background-color: #4CAF50;\n color: white;\n padding: 8px 16px;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n margin-top: 10px;\n}\n\n.sign-button:hover {\n background-color: #45a049;\n}\n\n.sign-button:disabled {\n background-color: #cccccc;\n cursor: not-allowed;\n}\n\n.modal-document {\n background: white;\n border-radius: 8px;\n max-width: 800px;\n width: 90%;\n max-height: 95vh;\n overflow-y: auto;\n position: relative;\n}\n\n.document-details {\n padding: 20px;\n}\n\n.info-section {\n margin: 20px 0;\n background: #f8f9fa;\n padding: 15px;\n border-radius: 6px;\n}\n\n.info-row {\n display: flex;\n justify-content: space-between;\n margin-bottom: 10px;\n}\n\n.label {\n font-weight: bold;\n color: #666;\n}\n\n.description-section {\n margin: 20px 0;\n}\n\n.signatures-section {\n margin: 20px 0;\n}\n\n.signature-item {\n display: flex;\n justify-content: space-between;\n padding: 8px;\n border-bottom: 1px solid #eee;\n}\n\n.signature-item.signed {\n background-color: #e8f5e9;\n}\n\n.signature-item.pending {\n background-color: #fff3e0;\n}\n\n.files-section {\n margin: 20px 0;\n}\n\n.file-item {\n display: flex;\n align-items: center;\n padding: 8px;\n background: #f8f9fa;\n margin-bottom: 5px;\n border-radius: 4px;\n}\n\n.file-icon {\n margin-right: 10px;\n}\n\n.download-link {\n margin-left: auto;\n}\n\n.confirmation-section {\n margin-top: 30px;\n text-align: center;\n}\n\n.warning-text {\n color: #f44336;\n margin-bottom: 15px;\n}\n\n.sign-confirm-btn {\n background-color: #4CAF50;\n color: white;\n padding: 10px 20px;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n}\n\n.sign-confirm-btn:hover {\n background-color: #45a049;\n}\n\n.signature-slider-container {\n margin: 20px 20%;\n padding: 10px;\n}\n\n.slider-track {\n position: relative;\n background: #e0e0e0;\n height: 40px;\n border-radius: 20px;\n display: flex;\n align-items: center;\n overflow: hidden;\n}\n\n.slider-handle {\n position: absolute;\n left: 0;\n width: 40px;\n height: 40px;\n background: #4CAF50;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n touch-action: none;\n z-index: 1;\n}\n\n.slider-arrow {\n color: white;\n font-size: 20px;\n}\n\n.slider-text {\n width: 100%;\n text-align: center;\n color: #666;\n user-select: none;\n}";
class SignatureComponent extends HTMLElement {
_callback;
signatureElement = null;
constructor() {
super();
console.log("INIT");
this.attachShadow({ mode: "open" });
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() {
{
const service = await Services.getInstance();
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) {
const signatureElement = document.createElement("signature-element");
this.shadowRoot.innerHTML = ``;
this.shadowRoot.appendChild(signatureElement);
}
}
}
customElements.define("signature-component", SignatureComponent);
export { SignatureComponent };