@@ -217,6 +225,7 @@ export default {
showDeleteFoldersModal: false,
selectedConversations: [],
selectedInboxes: [],
+ isContextMenuOpen: false,
};
},
computed: {
@@ -584,11 +593,12 @@ export default {
this.resetBulkActions();
}
},
- async onAssignAgent(agent) {
+ // Same method used in context menu, conversationId being passed from there.
+ async onAssignAgent(agent, conversationId = null) {
try {
await this.$store.dispatch('bulkActions/process', {
type: 'Conversation',
- ids: this.selectedConversations,
+ ids: conversationId || this.selectedConversations,
fields: {
assignee_id: agent.id,
},
@@ -599,11 +609,12 @@ export default {
this.showAlert(this.$t('BULK_ACTION.ASSIGN_FAILED'));
}
},
- async onAssignLabels(labels) {
+ // Same method used in context menu, conversationId being passed from there.
+ async onAssignLabels(labels, conversationId = null) {
try {
await this.$store.dispatch('bulkActions/process', {
type: 'Conversation',
- ids: this.selectedConversations,
+ ids: conversationId || this.selectedConversations,
labels: {
add: labels,
},
@@ -629,12 +640,27 @@ export default {
this.showAlert(this.$t('BULK_ACTION.UPDATE.UPDATE_FAILED'));
}
},
+ toggleConversationStatus(conversationId, status, snoozedUntil) {
+ this.$store
+ .dispatch('toggleStatus', {
+ conversationId,
+ status,
+ snoozedUntil,
+ })
+ .then(() => {
+ this.showAlert(this.$t('CONVERSATION.CHANGE_STATUS'));
+ this.isLoading = false;
+ });
+ },
allSelectedConversationsStatus(status) {
if (!this.selectedConversations.length) return false;
return this.selectedConversations.every(item => {
return this.$store.getters.getConversationById(item).status === status;
});
},
+ onContextMenuToggle(state) {
+ this.isContextMenuOpen = state;
+ },
},
};
@@ -647,6 +673,13 @@ export default {
margin-bottom: var(--space-normal);
}
+.conversations-list {
+ // Prevent the list from scrolling if the submenu is opened
+ &.is-context-menu-open {
+ overflow: hidden !important;
+ }
+}
+
.conversations-list-wrap {
flex-shrink: 0;
width: 34rem;
diff --git a/app/javascript/dashboard/components/buttons/ResolveAction.vue b/app/javascript/dashboard/components/buttons/ResolveAction.vue
index 810172ae5..afcdc0b1d 100644
--- a/app/javascript/dashboard/components/buttons/ResolveAction.vue
+++ b/app/javascript/dashboard/components/buttons/ResolveAction.vue
@@ -113,6 +113,7 @@
import { mapGetters } from 'vuex';
import { mixin as clickaway } from 'vue-clickaway';
import alertMixin from 'shared/mixins/alertMixin';
+import snoozeTimesMixin from 'dashboard/mixins/conversation/snoozeTimesMixin.js';
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import {
hasPressedAltAndEKey,
@@ -126,13 +127,6 @@ import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue';
import WootDropdownDivider from 'shared/components/ui/dropdown/DropdownDivider';
import wootConstants from '../../constants';
-import {
- getUnixTime,
- addHours,
- addWeeks,
- startOfTomorrow,
- startOfWeek,
-} from 'date-fns';
import {
CMD_REOPEN_CONVERSATION,
CMD_RESOLVE_CONVERSATION,
@@ -146,7 +140,7 @@ export default {
WootDropdownSubMenu,
WootDropdownDivider,
},
- mixins: [clickaway, alertMixin, eventListenerMixins],
+ mixins: [clickaway, alertMixin, eventListenerMixins, snoozeTimesMixin],
props: { conversationId: { type: [String, Number], required: true } },
data() {
return {
@@ -178,16 +172,6 @@ export default {
showAdditionalActions() {
return !this.isPending && !this.isSnoozed;
},
- snoozeTimes() {
- return {
- // tomorrow = 9AM next day
- tomorrow: getUnixTime(addHours(startOfTomorrow(), 9)),
- // next week = 9AM Monday, next week
- nextWeek: getUnixTime(
- addHours(startOfWeek(addWeeks(new Date(), 1), { weekStartsOn: 1 }), 9)
- ),
- };
- },
},
mounted() {
bus.$on(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
diff --git a/app/javascript/dashboard/components/index.js b/app/javascript/dashboard/components/index.js
index d2614421c..5e58aa049 100644
--- a/app/javascript/dashboard/components/index.js
+++ b/app/javascript/dashboard/components/index.js
@@ -22,6 +22,7 @@ import Tabs from './ui/Tabs/Tabs';
import TabsItem from './ui/Tabs/TabsItem';
import Thumbnail from './widgets/Thumbnail.vue';
import ConfirmModal from './widgets/modal/ConfirmationModal.vue';
+import ContextMenu from './ui/ContextMenu.vue';
const WootUIKit = {
AvatarUploader,
@@ -47,6 +48,7 @@ const WootUIKit = {
TabsItem,
Thumbnail,
ConfirmModal,
+ ContextMenu,
install(Vue) {
const keys = Object.keys(this);
keys.pop(); // remove 'install' from keys
diff --git a/app/javascript/dashboard/components/ui/ContextMenu.vue b/app/javascript/dashboard/components/ui/ContextMenu.vue
new file mode 100644
index 000000000..b968cda19
--- /dev/null
+++ b/app/javascript/dashboard/components/ui/ContextMenu.vue
@@ -0,0 +1,53 @@
+
+
+
+
+
diff --git a/app/javascript/dashboard/components/widgets/conversation/ConversationCard.vue b/app/javascript/dashboard/components/widgets/conversation/ConversationCard.vue
index 7b90ef6eb..b3c36928c 100644
--- a/app/javascript/dashboard/components/widgets/conversation/ConversationCard.vue
+++ b/app/javascript/dashboard/components/widgets/conversation/ConversationCard.vue
@@ -10,6 +10,7 @@
@mouseenter="onCardHover"
@mouseleave="onCardLeave"
@click="cardClick(chat)"
+ @contextmenu="openContextMenu($event)"
>