diff --git a/app/javascript/dashboard/i18n/locale/en/internalChat.json b/app/javascript/dashboard/i18n/locale/en/internalChat.json index 97cd32e77..f8448a8c1 100644 --- a/app/javascript/dashboard/i18n/locale/en/internalChat.json +++ b/app/javascript/dashboard/i18n/locale/en/internalChat.json @@ -66,6 +66,7 @@ "DELETED": "This message was deleted", "SEND": "Send", "UPLOAD_FILE": "Upload File", + "DRAG_DROP": "Drop files here to attach", "MENTION_USER": "Mention a user", "MENTION_CONVERSATION": "Mention a conversation", "CONFIRM_DELETE": "Are you sure you want to delete this message?", diff --git a/app/javascript/dashboard/i18n/locale/pt_BR/internalChat.json b/app/javascript/dashboard/i18n/locale/pt_BR/internalChat.json index 822d5f1e3..94b560ae8 100644 --- a/app/javascript/dashboard/i18n/locale/pt_BR/internalChat.json +++ b/app/javascript/dashboard/i18n/locale/pt_BR/internalChat.json @@ -66,6 +66,7 @@ "DELETED": "Esta mensagem foi exclu\u00edda", "SEND": "Enviar", "UPLOAD_FILE": "Enviar Arquivo", + "DRAG_DROP": "Solte os arquivos aqui para anexar", "MENTION_USER": "Mencionar um usu\u00e1rio", "MENTION_CONVERSATION": "Mencionar uma conversa", "CONFIRM_DELETE": "Tem certeza que deseja excluir esta mensagem?", diff --git a/app/javascript/dashboard/routes/dashboard/internalChat/MessageEditor.vue b/app/javascript/dashboard/routes/dashboard/internalChat/MessageEditor.vue index 0c6b9fb4a..19938ce53 100644 --- a/app/javascript/dashboard/routes/dashboard/internalChat/MessageEditor.vue +++ b/app/javascript/dashboard/routes/dashboard/internalChat/MessageEditor.vue @@ -49,8 +49,10 @@ const editorContent = ref(props.initialContent); const attachedFiles = ref([]); const isMentionMenuOpen = ref(false); const isConversationMenuOpen = ref(false); +const isDragging = ref(false); let draftTimer = null; +let dragCounter = 0; const canSend = computed(() => { return ( @@ -147,6 +149,53 @@ function removeFile(index) { attachedFiles.value.splice(index, 1); } +function addFiles(fileList) { + const files = Array.from(fileList || []).filter(f => f && f.size > 0); + if (!files.length) return; + attachedFiles.value = [...attachedFiles.value, ...files]; +} + +function handlePaste(event) { + const files = event.clipboardData?.files; + if (!files?.length) return; + event.preventDefault(); + addFiles(files); +} + +function hasFileDrag(event) { + return event.dataTransfer?.types?.includes('Files'); +} + +function handleDragEnter(event) { + if (!hasFileDrag(event)) return; + event.preventDefault(); + dragCounter += 1; + isDragging.value = true; +} + +function handleDragOver(event) { + if (!hasFileDrag(event)) return; + event.preventDefault(); +} + +function handleDragLeave(event) { + if (!hasFileDrag(event)) return; + event.preventDefault(); + dragCounter -= 1; + if (dragCounter <= 0) { + dragCounter = 0; + isDragging.value = false; + } +} + +function handleDrop(event) { + if (!hasFileDrag(event)) return; + event.preventDefault(); + dragCounter = 0; + isDragging.value = false; + addFiles(event.dataTransfer?.files); +} + function filePreviewUrl(file) { return URL.createObjectURL(file); } @@ -185,7 +234,25 @@ defineExpose({ focus, setContent, getContent });