From 03b17490e9b78d2fbcfbf9e0b96750bd4bbbd4c5 Mon Sep 17 00:00:00 2001 From: Eduardo Medeiros Date: Wed, 15 Jan 2025 16:06:41 -0300 Subject: [PATCH 01/13] feat: add reply visual and logic --- package.json | 2 +- .../chats/MessageManager/ReplyMessage.vue | 186 ++++++++++++++++++ src/components/chats/MessageManager/index.vue | 63 ++++-- .../chats/chat/ChatMessages/index.vue | 33 +++- src/components/chats/chat/RoomMessages.vue | 1 + src/locales/en.json | 4 + src/locales/es.json | 3 + src/locales/pt_br.json | 3 + src/store/modules/chats/roomMessages.js | 1 + yarn.lock | 8 +- 10 files changed, 285 insertions(+), 19 deletions(-) create mode 100644 src/components/chats/MessageManager/ReplyMessage.vue diff --git a/package.json b/package.json index c93f70e12..b6a852246 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "translations:suggest-from-pt-br": "unified-translations --translations-file ./src/locales/translations.json --languages pt-br=./src/locales/pt_br.json,en=./src/locales/en.json,es=./src/locales/es.json --mode build --suggest \"pt-br:pt>en:en\" && unified-translations --translations-file ./src/locales/translations.json --languages pt-br=./src/locales/pt_br.json,en=./src/locales/en.json,es=./src/locales/es.json --mode reverse && unified-translations --translations-file ./src/locales/translations.json --languages pt-br=./src/locales/pt_br.json,en=./src/locales/en.json,es=./src/locales/es.json --mode build --suggest \"pt-br:pt>es\" && unified-translations --translations-file ./src/locales/translations.json --languages pt-br=./src/locales/pt_br.json,en=./src/locales/en.json,es=./src/locales/es.json --mode reverse" }, "dependencies": { - "@weni/unnnic-system": "^2.20.0", + "@weni/unnnic-system": "2.19.1-alpha.10", "axios": "^0.27.2", "core-js": "^3.8.3", "iframessa": "^2.0.0", diff --git a/src/components/chats/MessageManager/ReplyMessage.vue b/src/components/chats/MessageManager/ReplyMessage.vue new file mode 100644 index 000000000..9db3ffa4d --- /dev/null +++ b/src/components/chats/MessageManager/ReplyMessage.vue @@ -0,0 +1,186 @@ + + + + + diff --git a/src/components/chats/MessageManager/index.vue b/src/components/chats/MessageManager/index.vue index c13fca5b5..96a69fafc 100644 --- a/src/components/chats/MessageManager/index.vue +++ b/src/components/chats/MessageManager/index.vue @@ -16,9 +16,14 @@ v-if="isFileLoadingValueValid" :value="loadingFileValue" /> + import isMobile from 'is-mobile'; -import { mapActions, mapState } from 'pinia'; +import { mapActions, mapState, mapWritableState } from 'pinia'; import { useQuickMessageShared } from '@/store/modules/chats/quickMessagesShared'; import { useQuickMessages } from '@/store/modules/chats/quickMessages'; @@ -152,6 +157,7 @@ import MoreActionsOption from './MoreActionsOption.vue'; import LoadingBar from './LoadingBar.vue'; import SuggestionBox from './SuggestionBox.vue'; import CoPilot from './CoPilot.vue'; +import ReplyMessage from './ReplyMessage.vue'; export default { name: 'MessageManager', @@ -163,6 +169,7 @@ export default { SuggestionBox, MoreActionsOption, CoPilot, + ReplyMessage, }, props: { @@ -201,10 +208,11 @@ export default { computed: { ...mapState(useQuickMessageShared, ['quickMessagesShared']), ...mapState(useQuickMessages, ['quickMessages']), - ...mapState(useRooms, ['canUseCopilot']), + ...mapState(useRooms, ['canUseCopilot', 'activeRoom']), ...mapState(useDiscussions, { discussionId: (store) => store.activeDiscussion?.uuid, }), + ...mapWritableState(useRoomMessages, ['replyMessage']), isMobile() { return isMobile(); @@ -273,6 +281,12 @@ export default { }, }, + watch: { + 'activeRoom.uuid'() { + this.clearReplyMessage(); + }, + }, + methods: { ...mapActions(useDiscussionMessages, [ 'sendDiscussionMessage', @@ -292,6 +306,9 @@ export default { this.$refs.textBox.focus(); }); }, + clearReplyMessage() { + this.replyMessage = null; + }, clearAudio() { this.$refs.audioRecorder?.discard(); this.audioMessage = null; @@ -425,6 +442,7 @@ export default { }, updateAudioRecorderStatus(status) { this.audioRecorderStatus = status; + console.log(this.audioRecorderStatus); }, }, }; @@ -439,21 +457,36 @@ export default { gap: $unnnic-spacing-stack-xs; align-items: end; - &-box__container { - position: relative; + &-box { + &__container { + position: relative; - border: $unnnic-border-width-thinner solid $unnnic-color-neutral-cleanest; - border-radius: $unnnic-border-radius-sm; - background-color: $unnnic-color-neutral-snow; + height: 100%; - height: 100%; + display: flex; + flex-direction: column; + gap: $unnnic-spacing-nano; - &.focused { - border-color: $unnnic-color-neutral-clean; + &.focused { + border-color: $unnnic-color-neutral-clean; + } + + &.loading { + border-radius: 0 0 $unnnic-border-radius-sm $unnnic-border-radius-sm; + } + + &.recording { + border: $unnnic-border-width-thinner solid + $unnnic-color-neutral-cleanest; + border-radius: $unnnic-border-radius-sm; + background-color: $unnnic-color-neutral-snow; + } } - &.loading { - border-radius: 0 0 $unnnic-border-radius-sm $unnnic-border-radius-sm; + &__text-box { + border: $unnnic-border-width-thinner solid $unnnic-color-neutral-cleanest; + border-radius: $unnnic-border-radius-sm; + background-color: $unnnic-color-neutral-snow; } } @@ -480,7 +513,11 @@ export default { justify-content: flex-end; - padding-right: $unnnic-spacing-stack-sm; + padding: 10px; + + border: $unnnic-border-width-thinner solid $unnnic-color-neutral-cleanest; + border-radius: $unnnic-border-radius-sm; + background-color: $unnnic-color-neutral-snow; :deep(.audio-player) { width: auto; diff --git a/src/components/chats/chat/ChatMessages/index.vue b/src/components/chats/chat/ChatMessages/index.vue index 2e3bd280c..08cfb9c13 100644 --- a/src/components/chats/chat/ChatMessages/index.vue +++ b/src/components/chats/chat/ChatMessages/index.vue @@ -61,6 +61,10 @@ :status="messageStatus({ message })" :title="messageFormatTitle(new Date(message.created_on))" :signature="messageSignature(message)" + :enableReply="enableReply" + @reply=" + handlerMessageReply({ ...message, content_type: 'text' }) + " > {{ isGeolocation(message.media?.[0]) @@ -90,6 +94,17 @@ :status="messageStatus({ message })" :title="messageFormatTitle(new Date(message.created_on))" :signature="messageSignature(message)" + :enableReply="enableReply" + @reply=" + handlerMessageReply({ + ...message, + content_type: isImage(media) + ? 'image' + : isVideo(media) + ? 'video' + : 'audio', + }) + " @click="resendMedia({ message, media })" > @@ -176,7 +198,7 @@ diff --git a/src/components/chats/MessageManager/__tests__/ReplyMessage.spec.js b/src/components/chats/MessageManager/__tests__/ReplyMessage.spec.js new file mode 100644 index 000000000..7ad32ffa4 --- /dev/null +++ b/src/components/chats/MessageManager/__tests__/ReplyMessage.spec.js @@ -0,0 +1,43 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { mount, config } from '@vue/test-utils'; +import UnnnicSystem from '@/plugins/UnnnicSystem'; + +import { createI18n } from 'vue-i18n'; +import en from '@/locales/en.json'; + +const i18n = createI18n({ + legacy: false, + locale: 'en', + messages: { en }, + fallbackWarn: false, + missingWarn: false, +}); + +config.global.plugins = [i18n, UnnnicSystem]; + +import ReplyMessage from '../ReplyMessage.vue'; + +const messageTextMock = { + uuid: '1', + user: null, + room: '1', + contact: { name: 'Contact' }, + text: 'text message', + media: [], + content_type: 'text', +}; + +describe('ReplyMessage', () => { + let wrapper; + + beforeEach(() => { + wrapper = mount(ReplyMessage, { props: { replyMessage: messageTextMock } }); + }); + + it('renders text content correctly', () => { + console.log(wrapper.html()); + expect(wrapper.find('.reply-message__content-text').text()).toBe( + 'text message', + ); + }); +}); From bc171923281ee58596b1ad1991d689e3b308464e Mon Sep 17 00:00:00 2001 From: Eduardo Medeiros Date: Thu, 16 Jan 2025 10:35:40 -0300 Subject: [PATCH 04/13] test: add ReplyMessageBox tests --- .../{ReplyMessage.vue => ReplyMessageBox.vue} | 41 ++++-- .../__tests__/ReplyMessage.spec.js | 137 +++++++++++++++++- src/components/chats/MessageManager/index.vue | 6 +- 3 files changed, 165 insertions(+), 19 deletions(-) rename src/components/chats/MessageManager/{ReplyMessage.vue => ReplyMessageBox.vue} (81%) diff --git a/src/components/chats/MessageManager/ReplyMessage.vue b/src/components/chats/MessageManager/ReplyMessageBox.vue similarity index 81% rename from src/components/chats/MessageManager/ReplyMessage.vue rename to src/components/chats/MessageManager/ReplyMessageBox.vue index b30099dd1..0904fac3a 100644 --- a/src/components/chats/MessageManager/ReplyMessage.vue +++ b/src/components/chats/MessageManager/ReplyMessageBox.vue @@ -6,6 +6,7 @@

{{ props.replyMessage.user ? $t('you') : props.replyMessage.contact.name @@ -15,6 +16,7 @@

{{ props.replyMessage.text }}

@@ -23,8 +25,9 @@ -

+

{{ props.replyMessage.media[0]?.url?.split('/').at(-1) || props.replyMessage.media[0]?.file?.name @@ -35,8 +38,9 @@ -

+

{{ $t('image') }}

@@ -44,8 +48,9 @@ -

+

{{ $t('video') }}

@@ -53,40 +58,50 @@ -

{{ $t('audio_message') }} {{ audioDuration }}

+

+ {{ $t('audio_message') }} {{ audioDuration }} +

+ data-testid="content-audio-media" + />
@@ -109,6 +124,7 @@ const hasPreview = computed(() => onUpdated(() => { const audio = document.getElementById(props.replyMessage?.uuid); + if (audio) audio.addEventListener( 'loadedmetadata', @@ -183,8 +199,13 @@ onUpdated(() => { } &__media-preview { - width: 50px; - height: 50px; + width: 100%; + height: 100%; + object-fit: contain; + &-container { + width: 50px; + height: 50px; + } } } diff --git a/src/components/chats/MessageManager/__tests__/ReplyMessage.spec.js b/src/components/chats/MessageManager/__tests__/ReplyMessage.spec.js index 7ad32ffa4..bfaa5aad0 100644 --- a/src/components/chats/MessageManager/__tests__/ReplyMessage.spec.js +++ b/src/components/chats/MessageManager/__tests__/ReplyMessage.spec.js @@ -1,5 +1,5 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { mount, config } from '@vue/test-utils'; +import { mount, config, flushPromises } from '@vue/test-utils'; import UnnnicSystem from '@/plugins/UnnnicSystem'; import { createI18n } from 'vue-i18n'; @@ -15,7 +15,8 @@ const i18n = createI18n({ config.global.plugins = [i18n, UnnnicSystem]; -import ReplyMessage from '../ReplyMessage.vue'; +import ReplyMessageBox from '../ReplyMessageBox.vue'; +import { nextTick } from 'vue'; const messageTextMock = { uuid: '1', @@ -27,17 +28,141 @@ const messageTextMock = { content_type: 'text', }; -describe('ReplyMessage', () => { +describe('ReplyMessageBox', () => { let wrapper; beforeEach(() => { - wrapper = mount(ReplyMessage, { props: { replyMessage: messageTextMock } }); + wrapper = mount(ReplyMessageBox, { + props: { replyMessage: messageTextMock }, + }); }); it('renders text content correctly', () => { - console.log(wrapper.html()); - expect(wrapper.find('.reply-message__content-text').text()).toBe( + expect(wrapper.find('[data-testid="content-text"]').text()).toBe( 'text message', ); }); + + it('renders attachment content correctly', async () => { + await wrapper.setProps({ + replyMessage: { + ...messageTextMock, + content_type: 'attachment', + media: [ + { + content_type: 'application/pdf', + url: 'http://exmaple.com/file.pdf', + }, + ], + }, + }); + + const icon = wrapper.findComponent( + '[data-testid="content-attachment-icon"]', + ); + const text = wrapper.find('[data-testid="content-attachment"]'); + + expect(icon.props().icon).toBe('article'); + + expect(text.text()).toContain('file.pdf'); + }); + + it('renders image content correctly', async () => { + await wrapper.setProps({ + replyMessage: { + ...messageTextMock, + content_type: 'image', + media: [ + { + content_type: 'image/png', + url: 'http://example.com/image.png', + }, + ], + }, + }); + + const icon = wrapper.findComponent('[data-testid="content-image-icon"]'); + const text = wrapper.find('[data-testid="content-image"]'); + const preview = wrapper.find('[data-testid="preview-image"]'); + + expect(icon.props().icon).toBe('image'); + + expect(text.text()).toContain(wrapper.vm.$t('image')); + + expect(preview.attributes().src).toBe('http://example.com/image.png'); + }); + + it('renders video content correctly', async () => { + await wrapper.setProps({ + replyMessage: { + ...messageTextMock, + content_type: 'video', + media: [ + { + content_type: 'video/mp4', + url: 'http://example.com/video.mp4', + }, + ], + }, + }); + + const icon = wrapper.findComponent('[data-testid="content-video-icon"]'); + const text = wrapper.find('[data-testid="content-video"]'); + const preview = wrapper.find('[data-testid="preview-video"]'); + + expect(icon.props().icon).toBe('videocam'); + + expect(text.text()).toContain(wrapper.vm.$t('video')); + + expect(preview.attributes().src).toBe('http://example.com/video.mp4'); + }); + + it('renders audio content correctly', async () => { + await wrapper.setProps({ + replyMessage: { + ...messageTextMock, + content_type: 'audio', + media: [ + { + content_type: 'audio/mp3', + url: 'http://example.com/audio.mp3', + }, + ], + }, + }); + + const icon = wrapper.findComponent('[data-testid="content-audio-icon"]'); + const text = wrapper.find('[data-testid="content-audio"]'); + + expect(icon.props().icon).toBe('mic'); + + expect(text.text()).toContain(wrapper.vm.$t('audio_message')); + }); + + it('emits close event when close icon is clicked', async () => { + await wrapper.find('[data-testid="close-icon"]').trigger('click'); + expect(wrapper.emitted('close')).toBeTruthy(); + }); + + it('applies correct class and text for user message', async () => { + await wrapper.setProps({ replyMessage: { ...messageTextMock, user: {} } }); + + expect(wrapper.classes()).toContain('reply-message--you'); + + const contactName = wrapper.find('[data-testid="contact-name"]'); + + expect(contactName.text()).toBe(wrapper.vm.$t('you')); + }); + + it('applies correct class and text for contact message', async () => { + await wrapper.setProps({ + replyMessage: { ...messageTextMock, contact: { name: 'Contact' } }, + }); + + expect(wrapper.classes()).toContain('reply-message--contact'); + + const contactName = wrapper.find('[data-testid="contact-name"]'); + + expect(contactName.text()).toBe('Contact'); + }); }); diff --git a/src/components/chats/MessageManager/index.vue b/src/components/chats/MessageManager/index.vue index 8ed963dee..d2759f06c 100644 --- a/src/components/chats/MessageManager/index.vue +++ b/src/components/chats/MessageManager/index.vue @@ -16,7 +16,7 @@ v-if="isFileLoadingValueValid" :value="loadingFileValue" /> - @@ -157,7 +157,7 @@ import MoreActionsOption from './MoreActionsOption.vue'; import LoadingBar from './LoadingBar.vue'; import SuggestionBox from './SuggestionBox.vue'; import CoPilot from './CoPilot.vue'; -import ReplyMessage from './ReplyMessage.vue'; +import ReplyMessageBox from './ReplyMessageBox.vue'; export default { name: 'MessageManager', @@ -169,7 +169,7 @@ export default { SuggestionBox, MoreActionsOption, CoPilot, - ReplyMessage, + ReplyMessageBox, }, props: { From c4437c873b51914e5eedc839a50bd4100e3b8492 Mon Sep 17 00:00:00 2001 From: Eduardo Medeiros Date: Thu, 16 Jan 2025 10:45:08 -0300 Subject: [PATCH 05/13] wip: remove not used imports --- .../chats/MessageManager/__tests__/ReplyMessage.spec.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/chats/MessageManager/__tests__/ReplyMessage.spec.js b/src/components/chats/MessageManager/__tests__/ReplyMessage.spec.js index bfaa5aad0..38819b6aa 100644 --- a/src/components/chats/MessageManager/__tests__/ReplyMessage.spec.js +++ b/src/components/chats/MessageManager/__tests__/ReplyMessage.spec.js @@ -1,5 +1,5 @@ -import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { mount, config, flushPromises } from '@vue/test-utils'; +import { describe, it, expect, beforeEach } from 'vitest'; +import { mount, config } from '@vue/test-utils'; import UnnnicSystem from '@/plugins/UnnnicSystem'; import { createI18n } from 'vue-i18n'; @@ -16,7 +16,6 @@ const i18n = createI18n({ config.global.plugins = [i18n, UnnnicSystem]; import ReplyMessageBox from '../ReplyMessageBox.vue'; -import { nextTick } from 'vue'; const messageTextMock = { uuid: '1', From b97aab825052142204af593bc0d850634d9854e4 Mon Sep 17 00:00:00 2001 From: Eduardo Medeiros Date: Thu, 16 Jan 2025 18:48:34 -0300 Subject: [PATCH 06/13] fix: change reply message to unnnic version --- package.json | 2 +- .../chats/MessageManager/ReplyMessageBox.vue | 211 ------------------ .../__tests__/ReplyMessage.spec.js | 167 -------------- src/components/chats/MessageManager/index.vue | 7 +- src/locales/en.json | 8 + src/locales/es.json | 8 + src/locales/pt_br.json | 8 + yarn.lock | 8 +- 8 files changed, 33 insertions(+), 386 deletions(-) delete mode 100644 src/components/chats/MessageManager/ReplyMessageBox.vue delete mode 100644 src/components/chats/MessageManager/__tests__/ReplyMessage.spec.js diff --git a/package.json b/package.json index 09d2412cf..bb97c02bb 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "translations:suggest-from-pt-br": "unified-translations --translations-file ./src/locales/translations.json --languages pt-br=./src/locales/pt_br.json,en=./src/locales/en.json,es=./src/locales/es.json --mode build --suggest \"pt-br:pt>en:en\" && unified-translations --translations-file ./src/locales/translations.json --languages pt-br=./src/locales/pt_br.json,en=./src/locales/en.json,es=./src/locales/es.json --mode reverse && unified-translations --translations-file ./src/locales/translations.json --languages pt-br=./src/locales/pt_br.json,en=./src/locales/en.json,es=./src/locales/es.json --mode build --suggest \"pt-br:pt>es\" && unified-translations --translations-file ./src/locales/translations.json --languages pt-br=./src/locales/pt_br.json,en=./src/locales/en.json,es=./src/locales/es.json --mode reverse" }, "dependencies": { - "@weni/unnnic-system": "2.19.1-alpha.10", + "@weni/unnnic-system": "2.20.1-alpha.2", "@sentry/vue": "^8.50.0", "axios": "^0.27.2", "core-js": "^3.8.3", diff --git a/src/components/chats/MessageManager/ReplyMessageBox.vue b/src/components/chats/MessageManager/ReplyMessageBox.vue deleted file mode 100644 index 0904fac3a..000000000 --- a/src/components/chats/MessageManager/ReplyMessageBox.vue +++ /dev/null @@ -1,211 +0,0 @@ - - - - - diff --git a/src/components/chats/MessageManager/__tests__/ReplyMessage.spec.js b/src/components/chats/MessageManager/__tests__/ReplyMessage.spec.js deleted file mode 100644 index 38819b6aa..000000000 --- a/src/components/chats/MessageManager/__tests__/ReplyMessage.spec.js +++ /dev/null @@ -1,167 +0,0 @@ -import { describe, it, expect, beforeEach } from 'vitest'; -import { mount, config } from '@vue/test-utils'; -import UnnnicSystem from '@/plugins/UnnnicSystem'; - -import { createI18n } from 'vue-i18n'; -import en from '@/locales/en.json'; - -const i18n = createI18n({ - legacy: false, - locale: 'en', - messages: { en }, - fallbackWarn: false, - missingWarn: false, -}); - -config.global.plugins = [i18n, UnnnicSystem]; - -import ReplyMessageBox from '../ReplyMessageBox.vue'; - -const messageTextMock = { - uuid: '1', - user: null, - room: '1', - contact: { name: 'Contact' }, - text: 'text message', - media: [], - content_type: 'text', -}; - -describe('ReplyMessageBox', () => { - let wrapper; - - beforeEach(() => { - wrapper = mount(ReplyMessageBox, { - props: { replyMessage: messageTextMock }, - }); - }); - - it('renders text content correctly', () => { - expect(wrapper.find('[data-testid="content-text"]').text()).toBe( - 'text message', - ); - }); - - it('renders attachment content correctly', async () => { - await wrapper.setProps({ - replyMessage: { - ...messageTextMock, - content_type: 'attachment', - media: [ - { - content_type: 'application/pdf', - url: 'http://exmaple.com/file.pdf', - }, - ], - }, - }); - - const icon = wrapper.findComponent( - '[data-testid="content-attachment-icon"]', - ); - const text = wrapper.find('[data-testid="content-attachment"]'); - - expect(icon.props().icon).toBe('article'); - - expect(text.text()).toContain('file.pdf'); - }); - - it('renders image content correctly', async () => { - await wrapper.setProps({ - replyMessage: { - ...messageTextMock, - content_type: 'image', - media: [ - { - content_type: 'image/png', - url: 'http://example.com/image.png', - }, - ], - }, - }); - - const icon = wrapper.findComponent('[data-testid="content-image-icon"]'); - const text = wrapper.find('[data-testid="content-image"]'); - const preview = wrapper.find('[data-testid="preview-image"]'); - - expect(icon.props().icon).toBe('image'); - - expect(text.text()).toContain(wrapper.vm.$t('image')); - - expect(preview.attributes().src).toBe('http://example.com/image.png'); - }); - - it('renders video content correctly', async () => { - await wrapper.setProps({ - replyMessage: { - ...messageTextMock, - content_type: 'video', - media: [ - { - content_type: 'video/mp4', - url: 'http://example.com/video.mp4', - }, - ], - }, - }); - - const icon = wrapper.findComponent('[data-testid="content-video-icon"]'); - const text = wrapper.find('[data-testid="content-video"]'); - const preview = wrapper.find('[data-testid="preview-video"]'); - - expect(icon.props().icon).toBe('videocam'); - - expect(text.text()).toContain(wrapper.vm.$t('video')); - - expect(preview.attributes().src).toBe('http://example.com/video.mp4'); - }); - - it('renders audio content correctly', async () => { - await wrapper.setProps({ - replyMessage: { - ...messageTextMock, - content_type: 'audio', - media: [ - { - content_type: 'audio/mp3', - url: 'http://example.com/audio.mp3', - }, - ], - }, - }); - - const icon = wrapper.findComponent('[data-testid="content-audio-icon"]'); - const text = wrapper.find('[data-testid="content-audio"]'); - - expect(icon.props().icon).toBe('mic'); - - expect(text.text()).toContain(wrapper.vm.$t('audio_message')); - }); - - it('emits close event when close icon is clicked', async () => { - await wrapper.find('[data-testid="close-icon"]').trigger('click'); - expect(wrapper.emitted('close')).toBeTruthy(); - }); - - it('applies correct class and text for user message', async () => { - await wrapper.setProps({ replyMessage: { ...messageTextMock, user: {} } }); - - expect(wrapper.classes()).toContain('reply-message--you'); - - const contactName = wrapper.find('[data-testid="contact-name"]'); - - expect(contactName.text()).toBe(wrapper.vm.$t('you')); - }); - - it('applies correct class and text for contact message', async () => { - await wrapper.setProps({ - replyMessage: { ...messageTextMock, contact: { name: 'Contact' } }, - }); - - expect(wrapper.classes()).toContain('reply-message--contact'); - - const contactName = wrapper.find('[data-testid="contact-name"]'); - - expect(contactName.text()).toBe('Contact'); - }); -}); diff --git a/src/components/chats/MessageManager/index.vue b/src/components/chats/MessageManager/index.vue index d2759f06c..8da6bd134 100644 --- a/src/components/chats/MessageManager/index.vue +++ b/src/components/chats/MessageManager/index.vue @@ -16,8 +16,11 @@ v-if="isFileLoadingValueValid" :value="loadingFileValue" /> - Date: Thu, 16 Jan 2025 18:54:05 -0300 Subject: [PATCH 07/13] fix: missing messageType props --- src/components/chats/MessageManager/index.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/chats/MessageManager/index.vue b/src/components/chats/MessageManager/index.vue index 8da6bd134..383c4c7bd 100644 --- a/src/components/chats/MessageManager/index.vue +++ b/src/components/chats/MessageManager/index.vue @@ -21,6 +21,7 @@ class="message-manager__reply-message" :replyMessage="replyMessage" showClose + messageType="received" @close="clearReplyMessage()" /> Date: Thu, 23 Jan 2025 18:13:38 -0300 Subject: [PATCH 08/13] feat: add replied message --- src/components/chats/chat/ChatMessages/index.vue | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/chats/chat/ChatMessages/index.vue b/src/components/chats/chat/ChatMessages/index.vue index 08cfb9c13..36939c2a8 100644 --- a/src/components/chats/chat/ChatMessages/index.vue +++ b/src/components/chats/chat/ChatMessages/index.vue @@ -62,6 +62,7 @@ :title="messageFormatTitle(new Date(message.created_on))" :signature="messageSignature(message)" :enableReply="enableReply" + :replyMessage="message.replied_message" @reply=" handlerMessageReply({ ...message, content_type: 'text' }) " @@ -95,6 +96,7 @@ :title="messageFormatTitle(new Date(message.created_on))" :signature="messageSignature(message)" :enableReply="enableReply" + :replyMessage="message.replied_message" @reply=" handlerMessageReply({ ...message, @@ -147,6 +149,7 @@ :title="messageFormatTitle(new Date(message.created_on))" :signature="messageSignature(message)" :enableReply="enableReply" + :replyMessage="message.replied_message" @reply=" handlerMessageReply({ ...message, From bce521f27576ecc0f9c3af5d49e31e8f38792b00 Mon Sep 17 00:00:00 2001 From: Eduardo Medeiros Date: Mon, 27 Jan 2025 14:40:21 -0300 Subject: [PATCH 09/13] fix: focus on reply message and textbox shadown --- package.json | 2 +- src/components/chats/MessageManager/index.vue | 7 +++++++ yarn.lock | 8 ++++---- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index bb97c02bb..f85992bc8 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "translations:suggest-from-pt-br": "unified-translations --translations-file ./src/locales/translations.json --languages pt-br=./src/locales/pt_br.json,en=./src/locales/en.json,es=./src/locales/es.json --mode build --suggest \"pt-br:pt>en:en\" && unified-translations --translations-file ./src/locales/translations.json --languages pt-br=./src/locales/pt_br.json,en=./src/locales/en.json,es=./src/locales/es.json --mode reverse && unified-translations --translations-file ./src/locales/translations.json --languages pt-br=./src/locales/pt_br.json,en=./src/locales/en.json,es=./src/locales/es.json --mode build --suggest \"pt-br:pt>es\" && unified-translations --translations-file ./src/locales/translations.json --languages pt-br=./src/locales/pt_br.json,en=./src/locales/en.json,es=./src/locales/es.json --mode reverse" }, "dependencies": { - "@weni/unnnic-system": "2.20.1-alpha.2", + "@weni/unnnic-system": "2.20.1-alpha.6", "@sentry/vue": "^8.50.0", "axios": "^0.27.2", "core-js": "^3.8.3", diff --git a/src/components/chats/MessageManager/index.vue b/src/components/chats/MessageManager/index.vue index 383c4c7bd..77f589022 100644 --- a/src/components/chats/MessageManager/index.vue +++ b/src/components/chats/MessageManager/index.vue @@ -287,6 +287,9 @@ export default { 'activeRoom.uuid'() { this.clearReplyMessage(); }, + replyMessage(newReplyMessage) { + if (newReplyMessage) this.$refs.textBox.focus(); + }, }, mounted() { @@ -463,6 +466,10 @@ export default { gap: $unnnic-spacing-stack-xs; align-items: end; + :deep(.reply-message) { + box-shadow: 0px 2px 5px -1px rgba(0, 0, 0, 0.1); + } + &-box { &__container { position: relative; diff --git a/yarn.lock b/yarn.lock index cfbd3e30e..12e5e5f01 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2024,10 +2024,10 @@ resolved "https://registry.yarnpkg.com/@weni/eslint-config/-/eslint-config-1.0.4.tgz#aa21eafb5ae220d78f306c2d0a08487dd5655bdc" integrity sha512-KZWyok6xvwCqJSXwS51mt801MLzVhiiAe2IgCf7e7OmlHfmjXwdL4A3t93dMXRi6EhX9RIhpfRTuZiFgulw0Og== -"@weni/unnnic-system@2.20.1-alpha.2": - version "2.20.1-alpha.2" - resolved "https://registry.yarnpkg.com/@weni/unnnic-system/-/unnnic-system-2.20.1-alpha.2.tgz#d72e52f903d501e973a499c49701ae86eab11f45" - integrity sha512-DjJiOnIsYxM1R80vW3RAQSbfD3jAkXTyynn50zVdEugl+coU8RmqVX2Gik8GW22p+hOo+blFzBlzKIaP5pEHfg== +"@weni/unnnic-system@2.20.1-alpha.6": + version "2.20.1-alpha.6" + resolved "https://registry.yarnpkg.com/@weni/unnnic-system/-/unnnic-system-2.20.1-alpha.6.tgz#b9fad161d1b1256d940b922f0173f69b6c0825c8" + integrity sha512-FIX44aybD5aFRG1OHWHRv9yAgSLH93+6DQyoQbJIWm/R/W9oOsRkVDyORqr7LOiDK5yW5PdC28bdgYA9/HlTLQ== dependencies: "@emoji-mart/data" "^1.1.2" "@vueuse/components" "^10.4.1" From eb968f2d1173f0410899f5046afc5b858336d729 Mon Sep 17 00:00:00 2001 From: Eduardo Medeiros Date: Mon, 27 Jan 2025 14:54:47 -0300 Subject: [PATCH 10/13] fix: background color --- src/layouts/ChatsLayout/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts/ChatsLayout/index.vue b/src/layouts/ChatsLayout/index.vue index f9c4dee42..81d45be5a 100644 --- a/src/layouts/ChatsLayout/index.vue +++ b/src/layouts/ChatsLayout/index.vue @@ -243,7 +243,7 @@ section.chats-layout { height: 100%; - background-color: $unnnic-color-background-carpet; + background-color: rgba(253, 245, 233, 0.25); } .quick-message { From 6af9eb4596d80ed47f1dada08cbb26fc74c02432 Mon Sep 17 00:00:00 2001 From: Eduardo Medeiros Date: Mon, 27 Jan 2025 15:51:16 -0300 Subject: [PATCH 11/13] wip: clean reply message --- src/components/chats/MessageManager/index.vue | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/chats/MessageManager/index.vue b/src/components/chats/MessageManager/index.vue index 77f589022..d07e1620e 100644 --- a/src/components/chats/MessageManager/index.vue +++ b/src/components/chats/MessageManager/index.vue @@ -347,7 +347,7 @@ export default { if (event.key === 'Enter') { if (event.shiftKey) return; - this.sendTextBoxMessage(); + this.send(); event.preventDefault(); } }, @@ -389,10 +389,11 @@ export default { stopRecord() { this.$refs.audioRecorder?.stop(); }, - send() { + async send() { this.$refs.textBox?.clearTextarea(); - this.sendTextBoxMessage(); - this.sendAudio(); + await this.sendTextBoxMessage(); + await this.sendAudio(); + // this.replyMessage = null; }, async sendTextBoxMessage() { const message = this.textBoxMessage.trim(); From 6fc82b596fe4c22d388817581a9a8028d734844a Mon Sep 17 00:00:00 2001 From: Eduardo Medeiros Date: Tue, 28 Jan 2025 10:16:54 -0300 Subject: [PATCH 12/13] fix: replied message service --- package.json | 2 +- src/components/chats/MessageManager/index.vue | 17 +++++++++++------ src/services/api/resources/chats/message.js | 9 +++++++-- src/store/modules/chats/roomMessages.js | 12 ++++++++++-- src/utils/messages.js | 6 ++++++ yarn.lock | 8 ++++---- 6 files changed, 39 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index f85992bc8..be5f0fcc6 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "translations:suggest-from-pt-br": "unified-translations --translations-file ./src/locales/translations.json --languages pt-br=./src/locales/pt_br.json,en=./src/locales/en.json,es=./src/locales/es.json --mode build --suggest \"pt-br:pt>en:en\" && unified-translations --translations-file ./src/locales/translations.json --languages pt-br=./src/locales/pt_br.json,en=./src/locales/en.json,es=./src/locales/es.json --mode reverse && unified-translations --translations-file ./src/locales/translations.json --languages pt-br=./src/locales/pt_br.json,en=./src/locales/en.json,es=./src/locales/es.json --mode build --suggest \"pt-br:pt>es\" && unified-translations --translations-file ./src/locales/translations.json --languages pt-br=./src/locales/pt_br.json,en=./src/locales/en.json,es=./src/locales/es.json --mode reverse" }, "dependencies": { - "@weni/unnnic-system": "2.20.1-alpha.6", + "@weni/unnnic-system": "2.20.1-alpha.8", "@sentry/vue": "^8.50.0", "axios": "^0.27.2", "core-js": "^3.8.3", diff --git a/src/components/chats/MessageManager/index.vue b/src/components/chats/MessageManager/index.vue index d07e1620e..18bfb82b9 100644 --- a/src/components/chats/MessageManager/index.vue +++ b/src/components/chats/MessageManager/index.vue @@ -390,23 +390,27 @@ export default { this.$refs.audioRecorder?.stop(); }, async send() { + let repliedMessage = null; + if (this.replyMessage) { + repliedMessage = { ...this.replyMessage }; + this.replyMessage = null; + } this.$refs.textBox?.clearTextarea(); - await this.sendTextBoxMessage(); - await this.sendAudio(); - // this.replyMessage = null; + await this.sendTextBoxMessage(repliedMessage); + await this.sendAudio(repliedMessage); }, - async sendTextBoxMessage() { + async sendTextBoxMessage(repliedMessage) { const message = this.textBoxMessage.trim(); if (message) { this.clearTextBox(); if (this.discussionId) { await this.sendDiscussionMessage(message); } else { - await this.sendRoomMessage(message); + await this.sendRoomMessage(message, repliedMessage); } } }, - async sendAudio() { + async sendAudio(repliedMessage) { if (this.audioRecorderStatus === 'recording') { await this.stopRecord(); } @@ -430,6 +434,7 @@ export default { const sendPayload = { files: [audio], updateLoadingFiles, + repliedMessage, }; if (this.discussionId) { diff --git a/src/services/api/resources/chats/message.js b/src/services/api/resources/chats/message.js index 2ff04361e..5e2ea12f1 100644 --- a/src/services/api/resources/chats/message.js +++ b/src/services/api/resources/chats/message.js @@ -69,12 +69,13 @@ export default { return response.data; }, - async sendRoomMessage(roomId, { text, user_email, seen }) { + async sendRoomMessage(roomId, { text, user_email, seen, repliedMessageId }) { const response = await http.post('/msg/', { room: roomId, text, user_email, seen, + replied_message_id: repliedMessageId, }); return response.data; }, @@ -89,7 +90,10 @@ export default { return response.data; }, - async sendRoomMedia(roomId, { user_email, media, updateLoadingFiles }) { + async sendRoomMedia( + roomId, + { user_email, media, updateLoadingFiles, repliedMessageId }, + ) { const msg = await this.sendRoomMessage(roomId, { text: '', user_email, @@ -102,6 +106,7 @@ export default { content_type: media.type, message: msg.uuid, media_file: media, + replied_message_id: repliedMessageId, }, { onUploadProgress: (event) => { diff --git a/src/store/modules/chats/roomMessages.js b/src/store/modules/chats/roomMessages.js index 8833b25e3..1c273d097 100644 --- a/src/store/modules/chats/roomMessages.js +++ b/src/store/modules/chats/roomMessages.js @@ -158,7 +158,7 @@ export const useRoomMessages = defineStore('roomMessages', { } }, - async sendRoomMessage(text) { + async sendRoomMessage(text, repliedMessage) { const roomsStore = useRooms(); const { activeRoom } = roomsStore; if (!activeRoom) return; @@ -168,11 +168,13 @@ export const useRoomMessages = defineStore('roomMessages', { itemUuid: activeRoom.uuid, itemUser: activeRoom.user, message: text, + repliedMessage: repliedMessage, sendItemMessage: () => Message.sendRoomMessage(activeRoom.uuid, { text, user_email: activeRoom.user.email, seen: true, + repliedMessageId: repliedMessage?.uuid, }), addMessage: (message) => this.handlingAddMessage({ message }), addSortedMessage: (message) => this.addRoomMessageSorted({ message }), @@ -181,7 +183,11 @@ export const useRoomMessages = defineStore('roomMessages', { }); }, - async sendRoomMedias({ files: medias, updateLoadingFiles }) { + async sendRoomMedias({ + files: medias, + updateLoadingFiles, + repliedMessage, + }) { const roomsStore = useRooms(); const { activeRoom } = roomsStore; if (!activeRoom) return; @@ -191,11 +197,13 @@ export const useRoomMessages = defineStore('roomMessages', { itemUuid: activeRoom.uuid, itemUser: activeRoom.user, medias, + repliedMessage: repliedMessage, sendItemMedia: (media) => Message.sendRoomMedia(activeRoom.uuid, { user_email: activeRoom.user.email, media, updateLoadingFiles, + repliedMessageId: repliedMessage?.uuid, }), addMessage: (message) => this.handlingAddMessage({ message }), addSortedMessage: (message) => this.addRoomMessageSorted({ message }), diff --git a/src/utils/messages.js b/src/utils/messages.js index d63cd7ed0..e0f9aa58a 100644 --- a/src/utils/messages.js +++ b/src/utils/messages.js @@ -23,6 +23,7 @@ export function createTemporaryMessage({ itemUser = {}, message = '', medias = [], + repliedMessage = null, }) { return { uuid: Date.now().toString(), @@ -32,6 +33,7 @@ export function createTemporaryMessage({ [itemType]: itemUuid, seen: true, user: itemUser, + replied_message: repliedMessage, }; } @@ -177,6 +179,7 @@ export async function sendMessage({ itemUuid, itemUser, message, + repliedMessage, sendItemMessage, addMessage, addSortedMessage, @@ -192,6 +195,7 @@ export async function sendMessage({ itemUuid, itemUser, message, + repliedMessage, }); addMessage(temporaryMessage); @@ -241,6 +245,7 @@ export async function sendMedias({ itemUuid, itemUser, medias, + repliedMessage, sendItemMedia, addMessage, addFailedMessage, @@ -261,6 +266,7 @@ export async function sendMedias({ itemType, itemUuid, itemUser, + repliedMessage, medias: [ { preview: mediaPreview, file: media, content_type: media.type }, ], diff --git a/yarn.lock b/yarn.lock index 12e5e5f01..1f7ccc25f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2024,10 +2024,10 @@ resolved "https://registry.yarnpkg.com/@weni/eslint-config/-/eslint-config-1.0.4.tgz#aa21eafb5ae220d78f306c2d0a08487dd5655bdc" integrity sha512-KZWyok6xvwCqJSXwS51mt801MLzVhiiAe2IgCf7e7OmlHfmjXwdL4A3t93dMXRi6EhX9RIhpfRTuZiFgulw0Og== -"@weni/unnnic-system@2.20.1-alpha.6": - version "2.20.1-alpha.6" - resolved "https://registry.yarnpkg.com/@weni/unnnic-system/-/unnnic-system-2.20.1-alpha.6.tgz#b9fad161d1b1256d940b922f0173f69b6c0825c8" - integrity sha512-FIX44aybD5aFRG1OHWHRv9yAgSLH93+6DQyoQbJIWm/R/W9oOsRkVDyORqr7LOiDK5yW5PdC28bdgYA9/HlTLQ== +"@weni/unnnic-system@2.20.1-alpha.8": + version "2.20.1-alpha.8" + resolved "https://registry.yarnpkg.com/@weni/unnnic-system/-/unnnic-system-2.20.1-alpha.8.tgz#2786cba4c2e61de0b80af3a608a96b591021eb2d" + integrity sha512-l9WxQBCu3WeWs/JlhOOQ9RLKFH+MPP1nvWSwJ0msTCwdDIYDDd6nA0EUdADKwB9Rku0XNrNDWATcTpd00SRGSA== dependencies: "@emoji-mart/data" "^1.1.2" "@vueuse/components" "^10.4.1" From 73ef2afd5fb8c64c5ce82595f2cef0b3c0aed04b Mon Sep 17 00:00:00 2001 From: Eduardo Medeiros Date: Tue, 28 Jan 2025 10:58:43 -0300 Subject: [PATCH 13/13] fix: tests --- src/utils/__tests__/messages/sendMedias.spec.js | 1 + src/utils/__tests__/messages/sendMessages.spec.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/utils/__tests__/messages/sendMedias.spec.js b/src/utils/__tests__/messages/sendMedias.spec.js index 3c06ded15..d6f87570d 100644 --- a/src/utils/__tests__/messages/sendMedias.spec.js +++ b/src/utils/__tests__/messages/sendMedias.spec.js @@ -97,6 +97,7 @@ describe('Messages utils', () => { ], seen: true, created_on: expect.any(String), + replied_message: null, }; // Verify temporary messages were created and added diff --git a/src/utils/__tests__/messages/sendMessages.spec.js b/src/utils/__tests__/messages/sendMessages.spec.js index 3671be285..f35b46075 100644 --- a/src/utils/__tests__/messages/sendMessages.spec.js +++ b/src/utils/__tests__/messages/sendMessages.spec.js @@ -82,6 +82,7 @@ describe('Messages utils', () => { type1: 'uuid1', user: 'user1', text: 'Test message', + replied_message: null, media: [], seen: true, created_on: expect.any(String),