From 864f0a5a45aa0a33348b3ec834293674bff2e7e4 Mon Sep 17 00:00:00 2001 From: Talon Date: Tue, 12 Aug 2025 14:16:05 +0200 Subject: [PATCH] Fix some mobile layout problems --- .../dialogs/CameraCaptureDialog.vue | 16 +- .../components/dialogs/FileUploadDialog.vue | 49 +++++-- .../dialogs/VoiceRecordingDialog.vue | 16 +- frontend-vue/src/composables/useWebSocket.ts | 50 +++++-- frontend-vue/src/services/sync.ts | 2 +- frontend-vue/src/views/MainView.vue | 138 +++++++++++++++++- 6 files changed, 237 insertions(+), 34 deletions(-) diff --git a/frontend-vue/src/components/dialogs/CameraCaptureDialog.vue b/frontend-vue/src/components/dialogs/CameraCaptureDialog.vue index 95c2f50..8c38373 100644 --- a/frontend-vue/src/components/dialogs/CameraCaptureDialog.vue +++ b/frontend-vue/src/components/dialogs/CameraCaptureDialog.vue @@ -278,7 +278,21 @@ const sendPhoto = async () => { }) // Upload photo - await apiService.uploadFile(appStore.currentChannelId!, message.id, file) + const uploadedFile = await apiService.uploadFile(appStore.currentChannelId!, message.id, file) + + // Immediately update the local message with file metadata + const updatedMessage = { + ...message, + fileId: uploadedFile.id, + filePath: uploadedFile.file_path, + fileType: uploadedFile.file_type, + fileSize: uploadedFile.file_size, + originalName: uploadedFile.original_name, + fileCreatedAt: uploadedFile.created_at + } + + // Update the message in the store + appStore.updateMessage(message.id, updatedMessage) toastStore.success('Photo sent!') emit('sent') diff --git a/frontend-vue/src/components/dialogs/FileUploadDialog.vue b/frontend-vue/src/components/dialogs/FileUploadDialog.vue index 26201bf..915dc1b 100644 --- a/frontend-vue/src/components/dialogs/FileUploadDialog.vue +++ b/frontend-vue/src/components/dialogs/FileUploadDialog.vue @@ -139,25 +139,44 @@ const uploadFiles = async () => { error.value = '' try { - // Create a message first to attach files to - const message = await apiService.createMessage(appStore.currentChannelId, - `Uploaded ${selectedFiles.value.length} file${selectedFiles.value.length === 1 ? '' : 's'}`) - - // Upload each file - for (let i = 0; i < selectedFiles.value.length; i++) { - const file = selectedFiles.value[i] + // For single file, use the filename as message content + // For multiple files, show count + const messageContent = selectedFiles.value.length === 1 + ? selectedFiles.value[0].name + : `Uploaded ${selectedFiles.value.length} files` - try { - await apiService.uploadFile(appStore.currentChannelId, message.id, file) - uploadProgress.value[i] = 100 - } catch (fileError) { - console.error(`Failed to upload ${file.name}:`, fileError) - toastStore.error(`Failed to upload ${file.name}`) - uploadProgress.value[i] = 0 + // Create a message first to attach files to + const message = await apiService.createMessage(appStore.currentChannelId, messageContent) + + // Upload the first file (backend uses single file per message) + const file = selectedFiles.value[0] + + try { + const uploadedFile = await apiService.uploadFile(appStore.currentChannelId, message.id, file) + uploadProgress.value[0] = 100 + + // Immediately update the local message with file metadata + const updatedMessage = { + ...message, + fileId: uploadedFile.id, + filePath: uploadedFile.file_path, + fileType: uploadedFile.file_type, + fileSize: uploadedFile.file_size, + originalName: uploadedFile.original_name, + fileCreatedAt: uploadedFile.created_at } + + // Update the message in the store + appStore.updateMessage(message.id, updatedMessage) + + toastStore.success('File uploaded successfully!') + + } catch (fileError) { + console.error(`Failed to upload ${file.name}:`, fileError) + toastStore.error(`Failed to upload ${file.name}`) + uploadProgress.value[0] = 0 } - toastStore.success('Files uploaded successfully!') emit('uploaded') } catch (err) { diff --git a/frontend-vue/src/components/dialogs/VoiceRecordingDialog.vue b/frontend-vue/src/components/dialogs/VoiceRecordingDialog.vue index ca87da3..e433506 100644 --- a/frontend-vue/src/components/dialogs/VoiceRecordingDialog.vue +++ b/frontend-vue/src/components/dialogs/VoiceRecordingDialog.vue @@ -186,7 +186,21 @@ const sendVoiceMessage = async () => { }) // Upload voice file - await apiService.uploadFile(appStore.currentChannelId!, message.id, file) + const uploadedFile = await apiService.uploadFile(appStore.currentChannelId!, message.id, file) + + // Immediately update the local message with file metadata + const updatedMessage = { + ...message, + fileId: uploadedFile.id, + filePath: uploadedFile.file_path, + fileType: uploadedFile.file_type, + fileSize: uploadedFile.file_size, + originalName: uploadedFile.original_name, + fileCreatedAt: uploadedFile.created_at + } + + // Update the message in the store + appStore.updateMessage(message.id, updatedMessage) toastStore.success('Voice message sent!') clearRecording() diff --git a/frontend-vue/src/composables/useWebSocket.ts b/frontend-vue/src/composables/useWebSocket.ts index fc91950..fd7b0fd 100644 --- a/frontend-vue/src/composables/useWebSocket.ts +++ b/frontend-vue/src/composables/useWebSocket.ts @@ -19,7 +19,14 @@ export function useWebSocket() { channel_id: parseInt(data.channelId), // Convert channelId string to channel_id number content: data.content, created_at: data.createdAt || new Date().toISOString(), - file_id: data.fileId + file_id: data.fileId, + // Handle flattened file fields + fileId: data.fileId, + filePath: data.filePath, + fileType: data.fileType, + fileSize: data.fileSize, + originalName: data.originalName, + fileCreatedAt: data.fileCreatedAt } console.log('WebSocket: Transformed message:', message) console.log('Transformed content:', JSON.stringify(message.content)) @@ -32,26 +39,41 @@ export function useWebSocket() { } } - const handleMessageUpdated = (data: { id: string, content: string }) => { - appStore.updateMessage(parseInt(data.id), { content: data.content }) + const handleMessageUpdated = (data: any) => { + // Handle full message updates including file metadata + const messageUpdate: Partial = { + content: data.content + } + + // Handle flattened file fields from server + if (data.fileId) { + messageUpdate.fileId = data.fileId + messageUpdate.filePath = data.filePath + messageUpdate.fileType = data.fileType + messageUpdate.fileSize = data.fileSize + messageUpdate.originalName = data.originalName + messageUpdate.fileCreatedAt = data.fileCreatedAt + } + + appStore.updateMessage(parseInt(data.id), messageUpdate) } const handleMessageDeleted = (data: { id: string }) => { appStore.removeMessage(parseInt(data.id)) } - const handleFileUploaded = (data: FileAttachment) => { - // Find the message and add the file to it - const channelMessages = appStore.messages[data.channel_id] || [] - const messageIndex = channelMessages.findIndex(m => m.id === data.message_id) - if (messageIndex !== -1) { - const message = channelMessages[messageIndex] - const updatedMessage = { - ...message, - files: [...(message.files || []), data] - } - appStore.updateMessage(message.id, updatedMessage) + const handleFileUploaded = (data: any) => { + // Handle file upload events with flattened format + const messageUpdate: Partial = { + fileId: data.fileId, + filePath: data.filePath, + fileType: data.fileType, + fileSize: data.fileSize, + originalName: data.originalName, + fileCreatedAt: data.fileCreatedAt } + + appStore.updateMessage(data.message_id, messageUpdate) } const handleChannelCreated = (data: { channel: Channel }) => { diff --git a/frontend-vue/src/services/sync.ts b/frontend-vue/src/services/sync.ts index 29a32d2..9a6110c 100644 --- a/frontend-vue/src/services/sync.ts +++ b/frontend-vue/src/services/sync.ts @@ -40,7 +40,7 @@ export class SyncService { }) // Add/update with server messages (server wins for conflicts) - serverMessages.forEach(msg => { + serverMessages.forEach((msg: any) => { // Transform server message format to match our types const transformedMsg: ExtendedMessage = { id: msg.id, diff --git a/frontend-vue/src/views/MainView.vue b/frontend-vue/src/views/MainView.vue index e1166bb..5db0703 100644 --- a/frontend-vue/src/views/MainView.vue +++ b/frontend-vue/src/views/MainView.vue @@ -1,12 +1,39 @@