From fa1cbdf97e96ff4a104d1d287ee54eaf3a7f2756 Mon Sep 17 00:00:00 2001 From: Talon Date: Wed, 20 Aug 2025 22:59:14 +0200 Subject: [PATCH] Try to fix data messages not showing up after being sent without refresh --- .../dialogs/CameraCaptureDialog.vue | 14 +- .../dialogs/VoiceRecordingDialog.vue | 14 +- frontend-vue/src/services/sync.ts | 129 ++++++++++++++++-- frontend-vue/src/types/index.ts | 8 ++ 4 files changed, 140 insertions(+), 25 deletions(-) diff --git a/frontend-vue/src/components/dialogs/CameraCaptureDialog.vue b/frontend-vue/src/components/dialogs/CameraCaptureDialog.vue index 8c38373..a30a652 100644 --- a/frontend-vue/src/components/dialogs/CameraCaptureDialog.vue +++ b/frontend-vue/src/components/dialogs/CameraCaptureDialog.vue @@ -280,9 +280,13 @@ const sendPhoto = async () => { // Upload photo const uploadedFile = await apiService.uploadFile(appStore.currentChannelId!, message.id, file) - // Immediately update the local message with file metadata - const updatedMessage = { - ...message, + // Create complete message with file metadata + const completeMessage = { + id: message.id, + channel_id: appStore.currentChannelId!, + content: message.content, + created_at: message.created_at, + file_id: uploadedFile.id, fileId: uploadedFile.id, filePath: uploadedFile.file_path, fileType: uploadedFile.file_type, @@ -291,8 +295,8 @@ const sendPhoto = async () => { fileCreatedAt: uploadedFile.created_at } - // Update the message in the store - appStore.updateMessage(message.id, updatedMessage) + // Add the complete message to the store (this will trigger immediate UI update) + appStore.addMessage(completeMessage) toastStore.success('Photo sent!') emit('sent') diff --git a/frontend-vue/src/components/dialogs/VoiceRecordingDialog.vue b/frontend-vue/src/components/dialogs/VoiceRecordingDialog.vue index e433506..75f8e84 100644 --- a/frontend-vue/src/components/dialogs/VoiceRecordingDialog.vue +++ b/frontend-vue/src/components/dialogs/VoiceRecordingDialog.vue @@ -188,9 +188,13 @@ const sendVoiceMessage = async () => { // Upload voice file const uploadedFile = await apiService.uploadFile(appStore.currentChannelId!, message.id, file) - // Immediately update the local message with file metadata - const updatedMessage = { - ...message, + // Create complete message with file metadata + const completeMessage = { + id: message.id, + channel_id: appStore.currentChannelId!, + content: message.content, + created_at: message.created_at, + file_id: uploadedFile.id, fileId: uploadedFile.id, filePath: uploadedFile.file_path, fileType: uploadedFile.file_type, @@ -199,8 +203,8 @@ const sendVoiceMessage = async () => { fileCreatedAt: uploadedFile.created_at } - // Update the message in the store - appStore.updateMessage(message.id, updatedMessage) + // Add the complete message to the store (this will trigger immediate UI update) + appStore.addMessage(completeMessage) toastStore.success('Voice message sent!') clearRecording() diff --git a/frontend-vue/src/services/sync.ts b/frontend-vue/src/services/sync.ts index 9a6110c..524aa98 100644 --- a/frontend-vue/src/services/sync.ts +++ b/frontend-vue/src/services/sync.ts @@ -77,7 +77,7 @@ export class SyncService { } /** - * Attempt to send all unsent messages + * Attempt to send all unsent messages (text and file messages) */ async retryUnsentMessages(): Promise { const appStore = this.getAppStore() @@ -86,28 +86,68 @@ export class SyncService { for (const unsentMsg of [...unsentMessages]) { try { - console.log(`Sending unsent message: ${unsentMsg.content}`) + console.log(`Sending unsent ${unsentMsg.messageType || 'text'} message: ${unsentMsg.content}`) - // Try to send the message - const response = await apiService.createMessage(unsentMsg.channelId, unsentMsg.content) - console.log(`Successfully sent unsent message, got ID: ${response.id}`) - - // Create the sent message - const sentMessage: ExtendedMessage = { - id: response.id, - channel_id: unsentMsg.channelId, - content: unsentMsg.content, - created_at: new Date().toISOString() + if (unsentMsg.messageType === 'voice' || unsentMsg.messageType === 'image') { + // Handle file message retry + if (!unsentMsg.fileData) { + console.error(`File message ${unsentMsg.id} missing file data, removing`) + appStore.removeUnsentMessage(unsentMsg.id) + continue + } + + // Create message and upload file + const response = await apiService.createMessage(unsentMsg.channelId, unsentMsg.content) + + // Create file from stored blob data + const file = new File([unsentMsg.fileData.blob], unsentMsg.fileData.fileName, { + type: unsentMsg.fileData.fileType + }) + + // Upload file + const uploadedFile = await apiService.uploadFile(unsentMsg.channelId, response.id, file) + + // Create complete message with file metadata + const sentMessage: ExtendedMessage = { + id: response.id, + channel_id: unsentMsg.channelId, + content: unsentMsg.content, + created_at: response.created_at, + file_id: uploadedFile.id, + fileId: uploadedFile.id, + filePath: uploadedFile.file_path, + fileType: uploadedFile.file_type, + fileSize: uploadedFile.file_size, + originalName: uploadedFile.original_name, + fileCreatedAt: uploadedFile.created_at + } + + appStore.addMessage(sentMessage) + console.log(`Successfully sent unsent ${unsentMsg.messageType} message, got ID: ${response.id}`) + + } else { + // Handle text message retry (existing logic) + const response = await apiService.createMessage(unsentMsg.channelId, unsentMsg.content) + console.log(`Successfully sent unsent text message, got ID: ${response.id}`) + + // Create the sent message + const sentMessage: ExtendedMessage = { + id: response.id, + channel_id: unsentMsg.channelId, + content: unsentMsg.content, + created_at: new Date().toISOString() + } + + appStore.addMessage(sentMessage) } - // Add to messages and remove from unsent - appStore.addMessage(sentMessage) + // Remove from unsent messages appStore.removeUnsentMessage(unsentMsg.id) // Save state immediately after successful send to ensure UI updates await appStore.saveState() - console.log(`Moved unsent message ${unsentMsg.id} to sent messages with ID ${response.id}`) + console.log(`Moved unsent message ${unsentMsg.id} to sent messages`) console.log(`Unsent messages remaining: ${appStore.unsentMessages.length}`) } catch (error) { @@ -201,6 +241,65 @@ export class SyncService { throw error // Re-throw so caller knows it failed } } + + /** + * Send a file message with optimistic updates and offline support + */ + async sendFileMessage(channelId: number, content: string, file: File, messageType: 'voice' | 'image' = 'image'): Promise { + try { + console.log(`Optimistically sending ${messageType} message: ${content}`) + + // Try to send immediately + const message = await apiService.createMessage(channelId, content) + + // Upload file + const uploadedFile = await apiService.uploadFile(channelId, message.id, file) + + // Success - create complete message with file metadata + const completeMessage: ExtendedMessage = { + id: message.id, + channel_id: channelId, + content: content, + created_at: message.created_at, + file_id: uploadedFile.id, + fileId: uploadedFile.id, + filePath: uploadedFile.file_path, + fileType: uploadedFile.file_type, + fileSize: uploadedFile.file_size, + originalName: uploadedFile.original_name, + fileCreatedAt: uploadedFile.created_at + } + + const appStore = this.getAppStore() + appStore.addMessage(completeMessage) + console.log(`${messageType} message sent successfully with ID: ${message.id}`) + + } catch (error) { + console.warn(`Failed to send ${messageType} message immediately, queuing for later:`, error) + + // Queue file message for retry when back online + const unsentMessage: UnsentMessage = { + id: `unsent_${messageType}_${Date.now()}_${Math.random()}`, + channelId: channelId, + content: content, + timestamp: Date.now(), + retries: 0, + messageType: messageType, + fileData: { + blob: file, + fileName: file.name, + fileType: file.type, + fileSize: file.size + } + } + + const appStore = this.getAppStore() + appStore.addUnsentMessage(unsentMessage) + await appStore.saveState() + + throw error // Re-throw so caller knows it failed + } + } } export const syncService = new SyncService() \ No newline at end of file diff --git a/frontend-vue/src/types/index.ts b/frontend-vue/src/types/index.ts index 660b755..dc1040a 100644 --- a/frontend-vue/src/types/index.ts +++ b/frontend-vue/src/types/index.ts @@ -72,6 +72,14 @@ export interface UnsentMessage { content: string timestamp: number retries: number + // File message support (for future offline retry capability) + messageType?: 'text' | 'voice' | 'image' + fileData?: { + blob: Blob + fileName: string + fileType: string + fileSize: number + } } export interface AppSettings {