From 867df43089942598145b0d51b5e501e5b4855a75 Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Thu, 25 Jan 2024 14:49:03 +0100 Subject: [PATCH] feat(Poll): pop up new arrived polls for participants in the call Signed-off-by: Maksim Sukharev --- .../Message/MessagePart/MessageBody.vue | 13 +++++- src/components/PollViewer/PollViewer.vue | 28 +++++++++++++ src/store/messagesStore.js | 3 ++ src/store/pollStore.js | 41 ++++++++++++++++++- 4 files changed, 82 insertions(+), 3 deletions(-) diff --git a/src/components/MessagesList/MessagesGroup/Message/MessagePart/MessageBody.vue b/src/components/MessagesList/MessagesGroup/Message/MessagePart/MessageBody.vue index 1d37ade1fb4..62810021fcc 100644 --- a/src/components/MessagesList/MessagesGroup/Message/MessagePart/MessageBody.vue +++ b/src/components/MessagesList/MessagesGroup/Message/MessagePart/MessageBody.vue @@ -28,7 +28,7 @@ :class="{ 'system-message': isSystemMessage && !showJoinCallButton, 'deleted-message': isDeletedMessage, - 'call-started': showJoinCallButton, + 'message-highlighted': showJoinCallButton, }"> @@ -49,6 +49,7 @@
@@ -284,6 +285,14 @@ export default { return this.messageParameters?.file }, + isNewPollMessage() { + if (this.messageParameters?.object?.type !== 'talk-poll') { + return false + } + + return !!this.$store.getters.getNewPolls[this.messageParameters.object.id] + }, + hideDate() { return this.isTemporary || this.isDeleting || !!this.sendingFailure }, @@ -442,7 +451,7 @@ export default { padding: 0 20px; } - &.call-started { + &.message-highlighted { color: var(--color-text-light); background-color: var(--color-primary-element-light); padding: 10px; diff --git a/src/components/PollViewer/PollViewer.vue b/src/components/PollViewer/PollViewer.vue index 1a75a2df64f..ce29103da30 100644 --- a/src/components/PollViewer/PollViewer.vue +++ b/src/components/PollViewer/PollViewer.vue @@ -119,7 +119,9 @@ import NcProgressBar from '@nextcloud/vue/dist/Components/NcProgressBar.js' import PollVotersDetails from './PollVotersDetails.vue' +import { useIsInCall } from '../../composables/useIsInCall.js' import { POLL } from '../../constants.js' +import { EventBus } from '../../services/EventBus.js' export default { name: 'PollViewer', @@ -138,6 +140,12 @@ export default { PollIcon, }, + setup() { + return { + isInCall: useIsInCall(), + } + }, + data() { return { voteToSubmit: [], @@ -238,6 +246,10 @@ export default { } }, + id(value) { + this.$store.dispatch('hidePollToast', value) + }, + poll: { immediate: true, handler(value) { @@ -252,6 +264,14 @@ export default { }, }, + mounted() { + EventBus.$on('talk:poll-added', this.showPopup) + }, + + beforeDestroy() { + EventBus.$off('talk:poll-added', this.showPopup) + }, + methods: { getPollData() { if (!this.poll) { @@ -268,6 +288,14 @@ export default { : [] }, + showPopup({ token, message }) { + if (!this.isInCall) { + return + } + + this.$store.dispatch('addPollToast', { token, message }) + }, + dismissModal() { this.$store.dispatch('removeActivePoll') this.voteToSubmit = [] diff --git a/src/store/messagesStore.js b/src/store/messagesStore.js index 91962c6b603..4d4d25924fe 100644 --- a/src/store/messagesStore.js +++ b/src/store/messagesStore.js @@ -599,6 +599,9 @@ const actions = { if (message.messageParameters?.object || message.messageParameters?.file) { // Handle voice messages, shares with single file, polls, deck cards, e.t.c sharedItemsStore.addSharedItemFromMessage(token, message) + if (message.messageParameters?.object?.type === 'talk-poll') { + EventBus.$emit('talk:poll-added', { token, message }) + } } else if (Object.keys(message.messageParameters).some(key => key.startsWith('file'))) { // Handle shares with multiple files } diff --git a/src/store/pollStore.js b/src/store/pollStore.js index 77732950d69..5b2dfa6d782 100644 --- a/src/store/pollStore.js +++ b/src/store/pollStore.js @@ -22,7 +22,7 @@ import debounce from 'debounce' import Vue from 'vue' -import { showError } from '@nextcloud/dialogs' +import { showError, showInfo, TOAST_PERMANENT_TIMEOUT } from '@nextcloud/dialogs' import pollService from '../services/pollService.js' @@ -30,6 +30,7 @@ const state = { polls: {}, pollDebounceFunctions: {}, activePoll: null, + pollToastsQueue: {}, } const getters = { @@ -40,6 +41,10 @@ const getters = { activePoll: (state) => { return state.activePoll }, + + getNewPolls: (state) => { + return state.pollToastsQueue + }, } const mutations = { @@ -60,6 +65,17 @@ const mutations = { } }, + addPollToast(state, { pollId, toast }) { + Vue.set(state.pollToastsQueue, pollId, toast) + }, + + hidePollToast(state, id) { + if (state.pollToastsQueue[id]) { + state.pollToastsQueue[id].hideToast() + Vue.delete(state.pollToastsQueue, id) + } + }, + // Add debounce function for getting the poll data addDebounceGetPollDataFunction(state, { token, pollId, debounceGetPollDataFunction }) { if (!state.pollDebounceFunctions[token]) { @@ -147,6 +163,29 @@ const actions = { removeActivePoll(context) { context.commit('removeActivePoll') }, + + addPollToast(context, { token, message }) { + const pollId = message.messageParameters.object.id + const name = message.messageParameters.object.name + + const toast = showInfo(t('spreed', 'Poll "{name}" was created by {user}. Click to vote', { + name, + user: message.actorDisplayName, + }), { + onClick: () => { + if (!context.state.activePoll) { + context.dispatch('setActivePoll', { token, pollId, name }) + } + }, + timeout: TOAST_PERMANENT_TIMEOUT, + }) + + context.commit('addPollToast', { pollId, toast }) + }, + + hidePollToast(context, id) { + context.commit('hidePollToast', id) + }, } export default { state, mutations, getters, actions }