send_file_ok

This commit is contained in:
Pascal 2025-01-14 14:21:19 +01:00
parent 1b980fd53c
commit 397d32623d

View File

@ -454,7 +454,7 @@ class ChatElement extends HTMLElement {
messaging_id: processId, messaging_id: processId,
description: 'message_content', description: 'message_content',
metadata: { metadata: {
text: "Je suis un message automatique de réponse<EFBFBD><EFBFBD>", text: "Je suis un message automatique de réponse",
timestamp: timestamp + 1000, timestamp: timestamp + 1000,
sender: this.selectedMemberId, sender: this.selectedMemberId,
recipient: myAddresses[0], recipient: myAddresses[0],
@ -526,14 +526,13 @@ class ChatElement extends HTMLElement {
chatHeader.textContent = `Chat with ${emojis}`; chatHeader.textContent = `Chat with ${emojis}`;
messagesContainer.innerHTML = ''; messagesContainer.innerHTML = '';
// Ouvrir IndexedDB
const dbRequest = indexedDB.open('4nk'); const dbRequest = indexedDB.open('4nk');
dbRequest.onerror = () => { dbRequest.onerror = () => {
console.error("Database error:", dbRequest.error); console.error("Database error:", dbRequest.error);
}; };
dbRequest.onsuccess = (event) => { dbRequest.onsuccess = async (event) => {
const db = dbRequest.result; const db = dbRequest.result;
const transaction = db.transaction(['diffs'], 'readonly'); const transaction = db.transaction(['diffs'], 'readonly');
const store = transaction.objectStore('diffs'); const store = transaction.objectStore('diffs');
@ -547,7 +546,6 @@ class ChatElement extends HTMLElement {
if (cursor) { if (cursor) {
const record = cursor.value; 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' && if (record.description === 'message_content' &&
record.metadata && record.metadata &&
record.metadata.roleName === this.selectedRole && record.metadata.roleName === this.selectedRole &&
@ -558,7 +556,6 @@ class ChatElement extends HTMLElement {
} }
cursor.continue(); cursor.continue();
} else { } else {
// Trier les messages par timestamp
messages.sort((a, b) => a.metadata.timestamp - b.metadata.timestamp); messages.sort((a, b) => a.metadata.timestamp - b.metadata.timestamp);
for (const message of messages) { for (const message of messages) {
@ -573,14 +570,48 @@ class ChatElement extends HTMLElement {
const senderEmoji = await addressToEmoji(message.metadata.sender); const senderEmoji = await addressToEmoji(message.metadata.sender);
messageContent.innerHTML = ` // Vérifier si c'est un fichier
<div class="message-content"> if (message.metadata.type === 'file') {
<strong>${senderEmoji}</strong>: ${message.metadata.text} let fileContent = '';
</div> if (message.metadata.fileType.startsWith('image/')) {
<div class="message-time"> // Afficher l'image
${new Date(message.metadata.timestamp).toLocaleString('fr-FR')} fileContent = `
</div> <div class="file-preview">
`; <img src="${message.metadata.fileData}" alt="${message.metadata.fileName}" style="max-width: 200px; max-height: 200px;"/>
</div>
`;
} 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 = `
<div class="file-download">
<a href="${url}" download="${message.metadata.fileName}">
📎 ${message.metadata.fileName}
</a>
</div>
`;
}
messageContent.innerHTML = `
<div class="message-content">
<strong>${senderEmoji}</strong>: ${fileContent}
</div>
<div class="message-time">
${new Date(message.metadata.timestamp).toLocaleString('fr-FR')}
</div>
`;
} else {
// Message texte normal
messageContent.innerHTML = `
<div class="message-content">
<strong>${senderEmoji}</strong>: ${message.metadata.text}
</div>
<div class="message-time">
${new Date(message.metadata.timestamp).toLocaleString('fr-FR')}
</div>
`;
}
messageElement.appendChild(messageContent); messageElement.appendChild(messageContent);
messagesContainer.appendChild(messageElement); messagesContainer.appendChild(messageElement);
@ -589,10 +620,6 @@ class ChatElement extends HTMLElement {
this.scrollToBottom(messagesContainer); this.scrollToBottom(messagesContainer);
} }
}; };
cursorRequest.onerror = () => {
console.error("Error loading messages:", cursorRequest.error);
};
}; };
} catch (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) { private async toggleMembers(roleData: any, roleElement: HTMLElement) {
let memberList = roleElement.querySelector('.member-list'); let memberList = roleElement.querySelector('.member-list');
const roleName = roleElement.querySelector('.role-name')?.textContent || ''; const roleName = roleElement.querySelector('.role-name')?.textContent || '';
@ -871,9 +918,7 @@ class ChatElement extends HTMLElement {
try { try {
const myAddresses = await this.getMemberFromDevice(); const myAddresses = await this.getMemberFromDevice();
if (!myAddresses) { if (!myAddresses) throw new Error('No paired member found');
throw new Error('No paired member found');
}
let fileData: string; let fileData: string;
if (file.type.startsWith('image/')) { if (file.type.startsWith('image/')) {
@ -882,117 +927,102 @@ class ChatElement extends HTMLElement {
fileData = await this.readFileAsBase64(file); fileData = await this.readFileAsBase64(file);
} }
const newMessage = { const timestamp = Date.now();
id: Date.now(), const processId = this.getAttribute('process-id');
sender: myAddresses[0], const uniqueKey = `${processId}${timestamp}`;
text: `Fichier envoyé: ${file.name}`,
fileName: file.name, const dbRequest = indexedDB.open('4nk');
time: new Date().toLocaleString('fr-FR'),
type: 'file', dbRequest.onerror = (event) => {
class: 'message user' console.error("Database error:", dbRequest.error);
}; };
try { dbRequest.onsuccess = async (event) => {
const fileKey = `file_${newMessage.id}`; const db = dbRequest.result;
localStorage.setItem(fileKey, fileData); const transaction = db.transaction(['diffs'], 'readwrite');
} catch (storageError) { const store = transaction.objectStore('diffs');
console.error('Erreur de stockage du fichier:', storageError);
alert('Erreur lors du stockage du fichier. Essayez avec un fichier plus petit.');
return;
}
if (this.selectedMemberId) { try {
messageStore.addMessage(this.selectedMemberId, newMessage); // Message du fichier
this.messagesMock = messageStore.getMessages(); const fileTemplate = {
} value_commitment: uniqueKey,
messaging_id: processId,
const groupItem = this.shadowRoot?.querySelector('[data-process-id]'); description: 'message_content',
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,
metadata: { metadata: {
created_at: newMessage.time, text: `Fichier envoyé: ${file.name}`,
last_updated: newMessage.time, timestamp: timestamp,
sender: myAddresses[0], sender: myAddresses[0],
recipient: this.selectedMemberId, recipient: this.selectedMemberId,
messageState: this.messageState,
roleName: this.selectedRole,
type: 'file',
fileName: file.name, fileName: file.name,
fileType: file.type fileType: file.type,
fileData: fileData
} }
};
await new Promise<void>((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<void>((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<void>((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: { } catch (error) {
public: { console.error('❌ Transaction error:', error);
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]
}
} }
}; };
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) { } catch (error) {
console.error('Error sending file:', error); console.error('❌ Error in sendFile:', error);
} }
} }