diff --git a/frontend/apps/widget/src/components/ChatMessages.vue b/frontend/apps/widget/src/components/ChatMessages.vue index ed9350b5..4c377c91 100644 --- a/frontend/apps/widget/src/components/ChatMessages.vue +++ b/frontend/apps/widget/src/components/ChatMessages.vue @@ -47,7 +47,7 @@ message.author.type === 'contact' || message.author.type === 'visitor' ? [ 'text-primary-foreground rounded-br-sm', - message.status === 'sending' + message.status === 'sending' || message.status === 'uploading' ? 'bg-primary/60' : message.status === 'failed' ? 'bg-destructive/60' @@ -80,11 +80,19 @@ v-else-if="message.author.type === 'contact' || message.author.type === 'visitor'" class="flex items-center gap-1" > - +
- {{ $t('globals.messages.sending') }} + + {{ $t('globals.messages.sending') }} + + + {{ $t('globals.messages.uploading') }} +
{{ getMessageTime(message.created_at) }} diff --git a/frontend/apps/widget/src/components/MessageInput.vue b/frontend/apps/widget/src/components/MessageInput.vue index c8df2bf4..66a5fdf0 100644 --- a/frontend/apps/widget/src/components/MessageInput.vue +++ b/frontend/apps/widget/src/components/MessageInput.vue @@ -226,6 +226,23 @@ const handleFileUpload = async (files) => { isUploading.value = true emit('error', '') + + // Create pending file message immediately + const fileNames = Array.from(files) + .map((f) => f.name) + .join(', ') + + const trimmedFileNames = + fileNames.length > 40 ? fileNames.slice(0, 40).trimEnd() + '...' : fileNames + const pendingMessage = `${trimmedFileNames}` + const tempMessageID = chatStore.addPendingMessage( + chatStore.currentConversation.uuid, + pendingMessage, + userStore.isVisitor ? 'visitor' : 'contact', + userStore.userID, + Array.from(files) + ) + try { // Upload files using the widget API await api.uploadMedia(chatStore.currentConversation.uuid, files) @@ -233,8 +250,18 @@ const handleFileUpload = async (files) => { // Refresh conversation to get updated messages with attachments const resp = await api.getChatConversation(chatStore.currentConversation.uuid) const msgs = resp.data.data.messages + + // Remove the pending message since we're replacing all messages + if (tempMessageID) { + chatStore.removeMessage(chatStore.currentConversation.uuid, tempMessageID) + } + chatStore.replaceMessages(msgs) } catch (error) { + // Remove failed upload message + if (tempMessageID) { + chatStore.removeMessage(chatStore.currentConversation.uuid, tempMessageID) + } emit('error', handleHTTPError(error).message) } finally { isUploading.value = false diff --git a/frontend/apps/widget/src/store/chat.js b/frontend/apps/widget/src/store/chat.js index a37ee497..7d126035 100644 --- a/frontend/apps/widget/src/store/chat.js +++ b/frontend/apps/widget/src/store/chat.js @@ -70,7 +70,7 @@ export const useChatStore = defineStore('chat', () => { updateConversationListLastMessage(conversationUUID, message, shouldIncrementUnread) } - const addPendingMessage = (conversationUUID, messageText, authorType, authorId) => { + const addPendingMessage = (conversationUUID, messageText, authorType, authorId, files=[]) => { // Pending message is a temporary message that will be replaced with actual message later after sending. const pendingMessage = { content: messageText, @@ -85,7 +85,7 @@ export const useChatStore = defineStore('chat', () => { }, attachments: [], uuid: `pending-${Date.now()}`, - status: 'sending', + status: files.length > 0 ? 'uploading' : 'sending', created_at: new Date().toISOString() } messageCache.addMessage(conversationUUID, pendingMessage) diff --git a/i18n/en.json b/i18n/en.json index 06acd4a7..f1a1461b 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -252,6 +252,7 @@ "globals.messages.revokedSuccessfully": "{name} revoked successfully", "globals.messages.errorRevoking": "Error revoking {name}", "globals.messages.generatedSuccessfully": "{name} generated successfully", + "globals.messages.uploading": "Uploading {name}", "globals.messages.generate": "Generate {name}", "globals.messages.generated": "{name} generated", "globals.messages.regenerate": "Regenerate",