From 397d32623df9c9121a456c23524ac3479452fd71 Mon Sep 17 00:00:00 2001 From: Pascal Date: Tue, 14 Jan 2025 14:21:19 +0100 Subject: [PATCH] send_file_ok --- src/pages/chat/chat.ts | 266 +++++++++++++++++++++++------------------ 1 file changed, 148 insertions(+), 118 deletions(-) diff --git a/src/pages/chat/chat.ts b/src/pages/chat/chat.ts index 15be721..9629ad4 100755 --- a/src/pages/chat/chat.ts +++ b/src/pages/chat/chat.ts @@ -454,7 +454,7 @@ class ChatElement extends HTMLElement { messaging_id: processId, description: 'message_content', metadata: { - text: "Je suis un message automatique de réponse��", + text: "Je suis un message automatique de réponse", timestamp: timestamp + 1000, sender: this.selectedMemberId, recipient: myAddresses[0], @@ -526,14 +526,13 @@ class ChatElement extends HTMLElement { chatHeader.textContent = `Chat with ${emojis}`; messagesContainer.innerHTML = ''; - // Ouvrir IndexedDB const dbRequest = indexedDB.open('4nk'); dbRequest.onerror = () => { console.error("Database error:", dbRequest.error); }; - dbRequest.onsuccess = (event) => { + dbRequest.onsuccess = async (event) => { const db = dbRequest.result; const transaction = db.transaction(['diffs'], 'readonly'); const store = transaction.objectStore('diffs'); @@ -547,7 +546,6 @@ class ChatElement extends HTMLElement { if (cursor) { const record = cursor.value; - // Vérifier si c'est un message valide avec le bon role et les bons participants if (record.description === 'message_content' && record.metadata && record.metadata.roleName === this.selectedRole && @@ -558,7 +556,6 @@ class ChatElement extends HTMLElement { } cursor.continue(); } else { - // Trier les messages par timestamp messages.sort((a, b) => a.metadata.timestamp - b.metadata.timestamp); for (const message of messages) { @@ -573,14 +570,48 @@ class ChatElement extends HTMLElement { const senderEmoji = await addressToEmoji(message.metadata.sender); - messageContent.innerHTML = ` -
- ${senderEmoji}: ${message.metadata.text} -
-
- ${new Date(message.metadata.timestamp).toLocaleString('fr-FR')} -
- `; + // Vérifier si c'est un fichier + if (message.metadata.type === 'file') { + let fileContent = ''; + if (message.metadata.fileType.startsWith('image/')) { + // Afficher l'image + fileContent = ` +
+ ${message.metadata.fileName} +
+ `; + } else { + // Afficher un lien pour télécharger le fichier + const blob = this.base64ToBlob(message.metadata.fileData, message.metadata.fileType); + const url = URL.createObjectURL(blob); + fileContent = ` +
+ + 📎 ${message.metadata.fileName} + +
+ `; + } + + messageContent.innerHTML = ` +
+ ${senderEmoji}: ${fileContent} +
+
+ ${new Date(message.metadata.timestamp).toLocaleString('fr-FR')} +
+ `; + } else { + // Message texte normal + messageContent.innerHTML = ` +
+ ${senderEmoji}: ${message.metadata.text} +
+
+ ${new Date(message.metadata.timestamp).toLocaleString('fr-FR')} +
+ `; + } messageElement.appendChild(messageContent); messagesContainer.appendChild(messageElement); @@ -589,10 +620,6 @@ class ChatElement extends HTMLElement { this.scrollToBottom(messagesContainer); } }; - - cursorRequest.onerror = () => { - console.error("Error loading messages:", cursorRequest.error); - }; }; } catch (error) { @@ -600,6 +627,26 @@ class ChatElement extends HTMLElement { } } + // Ajouter cette méthode utilitaire pour convertir base64 en Blob + private base64ToBlob(base64: string, type: string): Blob { + const byteCharacters = atob(base64.split(',')[1]); + const byteArrays = []; + + for (let offset = 0; offset < byteCharacters.length; offset += 512) { + const slice = byteCharacters.slice(offset, offset + 512); + const byteNumbers = new Array(slice.length); + + for (let i = 0; i < slice.length; i++) { + byteNumbers[i] = slice.charCodeAt(i); + } + + const byteArray = new Uint8Array(byteNumbers); + byteArrays.push(byteArray); + } + + return new Blob(byteArrays, { type: type }); + } + private async toggleMembers(roleData: any, roleElement: HTMLElement) { let memberList = roleElement.querySelector('.member-list'); const roleName = roleElement.querySelector('.role-name')?.textContent || ''; @@ -871,9 +918,7 @@ class ChatElement extends HTMLElement { try { const myAddresses = await this.getMemberFromDevice(); - if (!myAddresses) { - throw new Error('No paired member found'); - } + if (!myAddresses) throw new Error('No paired member found'); let fileData: string; if (file.type.startsWith('image/')) { @@ -882,117 +927,102 @@ class ChatElement extends HTMLElement { fileData = await this.readFileAsBase64(file); } - const newMessage = { - id: Date.now(), - sender: myAddresses[0], - text: `Fichier envoyé: ${file.name}`, - fileName: file.name, - time: new Date().toLocaleString('fr-FR'), - type: 'file', - class: 'message user' + const timestamp = Date.now(); + const processId = this.getAttribute('process-id'); + const uniqueKey = `${processId}${timestamp}`; + + const dbRequest = indexedDB.open('4nk'); + + dbRequest.onerror = (event) => { + console.error("Database error:", dbRequest.error); }; - try { - const fileKey = `file_${newMessage.id}`; - localStorage.setItem(fileKey, fileData); - } catch (storageError) { - console.error('Erreur de stockage du fichier:', storageError); - alert('Erreur lors du stockage du fichier. Essayez avec un fichier plus petit.'); - return; - } + dbRequest.onsuccess = async (event) => { + const db = dbRequest.result; + const transaction = db.transaction(['diffs'], 'readwrite'); + const store = transaction.objectStore('diffs'); - if (this.selectedMemberId) { - messageStore.addMessage(this.selectedMemberId, newMessage); - this.messagesMock = messageStore.getMessages(); - } - - const groupItem = this.shadowRoot?.querySelector('[data-process-id]'); - const parentProcessId = groupItem?.getAttribute('data-process-id'); - - if (!parentProcessId) { - throw new Error('Parent process ID not found'); - } - - const messageTemplate = { - process_id: parentProcessId, - parent_id: null, - description: 'file_message', - messages: { - state: 'initial', - object: { - type: 'file', - content: fileData, + try { + // Message du fichier + const fileTemplate = { + value_commitment: uniqueKey, + messaging_id: processId, + description: 'message_content', metadata: { - created_at: newMessage.time, - last_updated: newMessage.time, + text: `Fichier envoyé: ${file.name}`, + timestamp: timestamp, sender: myAddresses[0], recipient: this.selectedMemberId, + messageState: this.messageState, + roleName: this.selectedRole, + type: 'file', fileName: file.name, - fileType: file.type + fileType: file.type, + fileData: fileData } + }; + + await new Promise((resolve, reject) => { + const request = store.add(fileTemplate); + request.onsuccess = () => { + console.log('✅ File message saved'); + resolve(); + }; + request.onerror = () => reject(request.error); + }); + + // Réponse automatique + const autoReplyTemplate = { + value_commitment: `${processId}${timestamp + 1000}`, + messaging_id: processId, + description: 'message_content', + metadata: { + text: "J'ai bien reçu votre fichier 📎", + timestamp: timestamp + 1000, + sender: this.selectedMemberId, + recipient: myAddresses[0], + messageState: this.messageState, + roleName: this.selectedRole + } + }; + + await new Promise((resolve, reject) => { + const request = store.add(autoReplyTemplate); + request.onsuccess = () => { + console.log('✅ Auto reply saved'); + if (myAddresses[0]) { + this.addNotification(myAddresses[0], autoReplyTemplate); + } + resolve(); + }; + request.onerror = () => reject(request.error); + }); + + // Attendre la fin de la transaction + await new Promise((resolve, reject) => { + transaction.oncomplete = () => { + console.log('✅ Transaction completed'); + resolve(); + }; + transaction.onerror = () => reject(transaction.error); + }); + + // Réinitialiser l'input file + const fileInput = this.shadowRoot?.querySelector('#file-input') as HTMLInputElement; + if (fileInput) fileInput.value = ''; + + // Recharger les messages + if (this.selectedMemberId) { + await this.loadMemberChat(this.selectedMemberId); } - }, - roles: { - public: { - members: [ - { sp_addresses: myAddresses }, - { sp_addresses: [this.selectedMemberId] } - ], - validation_rules: [ - { - quorum: 0.0, - fields: ['description', 'messages'], - min_sig_member: 0.0, - }, - ], - storages: [storageUrl] - }, - owner: { - members: [ - { sp_addresses: myAddresses }, - { sp_addresses: [this.selectedMemberId] } - ], - validation_rules: [ - { - quorum: 1.0, - fields: ['description', 'messages'], - min_sig_member: 1.0, - }, - ], - storages: [storageUrl] - } + + } catch (error) { + console.error('❌ Transaction error:', error); } }; - const result = await this.createMessagingProcess( - [{ sp_addresses: [this.selectedMemberId!] }], - 'relay_address', - 1, - JSON.stringify(messageTemplate), - 'file_message' - ); - - console.log('Final file message process:', { - template: messageTemplate, - result: result, - timestamp: new Date().toISOString() - }); - - const fileInput = this.shadowRoot?.querySelector('#file-input') as HTMLInputElement; - if (fileInput) fileInput.value = ''; - - this.loadMemberChat(this.selectedMemberId!); - - setTimeout(() => { - const autoReply = this.generateAutoReply(this.selectedMemberId!); - messageStore.addMessage(this.selectedMemberId!, autoReply); - this.messagesMock = messageStore.getMessages(); - this.loadMemberChat(this.selectedMemberId!); - - this.addNotification(this.selectedMemberId!, autoReply); - }, 1000); } catch (error) { - console.error('Error sending file:', error); + console.error('❌ Error in sendFile:', error); } }