diff --git a/app/javascript/dashboard/mixins/specs/uiSettings.spec.js b/app/javascript/dashboard/mixins/specs/uiSettings.spec.js
index fcde4a291..75e33d387 100644
--- a/app/javascript/dashboard/mixins/specs/uiSettings.spec.js
+++ b/app/javascript/dashboard/mixins/specs/uiSettings.spec.js
@@ -1,7 +1,9 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
-import uiSettingsMixin from '../uiSettings';
+import uiSettingsMixin, {
+ DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
+ DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
+} from '../uiSettings';
import Vuex from 'vuex';
-
const localVue = createLocalVue();
localVue.use(Vuex);
@@ -17,6 +19,8 @@ describe('uiSettingsMixin', () => {
display_rich_content_editor: false,
enter_to_send_enabled: false,
is_ct_labels_open: true,
+ conversation_sidebar_items_order: DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
+ contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
}),
};
store = new Vuex.Store({ actions, getters });
@@ -33,6 +37,8 @@ describe('uiSettingsMixin', () => {
display_rich_content_editor: false,
enter_to_send_enabled: false,
is_ct_labels_open: true,
+ conversation_sidebar_items_order: DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
+ contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
});
});
@@ -52,6 +58,8 @@ describe('uiSettingsMixin', () => {
display_rich_content_editor: false,
enter_to_send_enabled: true,
is_ct_labels_open: true,
+ conversation_sidebar_items_order: DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
+ contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
},
},
undefined
@@ -75,6 +83,8 @@ describe('uiSettingsMixin', () => {
display_rich_content_editor: false,
enter_to_send_enabled: false,
is_ct_labels_open: false,
+ conversation_sidebar_items_order: DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER,
+ contact_sidebar_items_order: DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER,
},
},
undefined
@@ -98,4 +108,36 @@ describe('uiSettingsMixin', () => {
).toEqual(false);
});
});
+
+ describe('#conversationSidebarItemsOrder', () => {
+ it('returns correct values', () => {
+ const Component = {
+ render() {},
+ title: 'TestComponent',
+ mixins: [uiSettingsMixin],
+ };
+ const wrapper = shallowMount(Component, { store, localVue });
+ expect(wrapper.vm.conversationSidebarItemsOrder).toEqual([
+ { name: 'conversation_info' },
+ { name: 'contact_attributes' },
+ { name: 'previous_conversation' },
+ { name: 'conversation_actions' },
+ ]);
+ });
+ });
+ describe('#contactSidebarItemsOrder', () => {
+ it('returns correct values', () => {
+ const Component = {
+ render() {},
+ title: 'TestComponent',
+ mixins: [uiSettingsMixin],
+ };
+ const wrapper = shallowMount(Component, { store, localVue });
+ expect(wrapper.vm.contactSidebarItemsOrder).toEqual([
+ { name: 'contact_attributes' },
+ { name: 'contact_labels' },
+ { name: 'previous_conversation' },
+ ]);
+ });
+ });
});
diff --git a/app/javascript/dashboard/mixins/uiSettings.js b/app/javascript/dashboard/mixins/uiSettings.js
index 3518f4497..b33f4df50 100644
--- a/app/javascript/dashboard/mixins/uiSettings.js
+++ b/app/javascript/dashboard/mixins/uiSettings.js
@@ -1,10 +1,28 @@
import { mapGetters } from 'vuex';
-
+export const DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER = [
+ { name: 'conversation_info' },
+ { name: 'contact_attributes' },
+ { name: 'previous_conversation' },
+ { name: 'conversation_actions' },
+];
+export const DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER = [
+ { name: 'contact_attributes' },
+ { name: 'contact_labels' },
+ { name: 'previous_conversation' },
+];
export default {
computed: {
...mapGetters({
uiSettings: 'getUISettings',
}),
+ conversationSidebarItemsOrder() {
+ const { conversation_sidebar_items_order: itemsOrder } = this.uiSettings;
+ return itemsOrder || DEFAULT_CONVERSATION_SIDEBAR_ITEMS_ORDER;
+ },
+ contactSidebarItemsOrder() {
+ const { contact_sidebar_items_order: itemsOrder } = this.uiSettings;
+ return itemsOrder || DEFAULT_CONTACT_SIDEBAR_ITEMS_ORDER;
+ },
},
methods: {
updateUISettings(uiSettings = {}) {
diff --git a/app/javascript/dashboard/routes/dashboard/contacts/components/ContactInfoPanel.vue b/app/javascript/dashboard/routes/dashboard/contacts/components/ContactInfoPanel.vue
index cba08b2d1..647baf65a 100644
--- a/app/javascript/dashboard/routes/dashboard/contacts/components/ContactInfoPanel.vue
+++ b/app/javascript/dashboard/routes/dashboard/contacts/components/ContactInfoPanel.vue
@@ -12,42 +12,71 @@
:contact="contact"
@panel-close="onClose"
/>
- toggleSidebarUIState('is_ct_custom_attr_open', value)"
+
-
-
-
- toggleSidebarUIState('is_ct_labels_open', value)"
- >
-
-
- toggleSidebarUIState('is_ct_prev_conv_open', value)"
- >
-
-
+
+
+
+
toggleSidebarUIState('is_ct_custom_attr_open', value)
+ "
+ >
+
+
+
+
+
+
toggleSidebarUIState('is_ct_labels_open', value)"
+ >
+
+
+
+
+
toggleSidebarUIState('is_ct_prev_conv_open', value)
+ "
+ >
+
+
+
+
+
+
@@ -58,7 +87,7 @@ import ContactInfo from 'dashboard/routes/dashboard/conversation/contact/Contact
import ContactLabel from 'dashboard/routes/dashboard/contacts/components/ContactLabels.vue';
import CustomAttributes from 'dashboard/routes/dashboard/conversation/customAttributes/CustomAttributes.vue';
import CustomAttributeSelector from 'dashboard/routes/dashboard/conversation/customAttributes/CustomAttributeSelector.vue';
-
+import draggable from 'vuedraggable';
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
export default {
@@ -69,6 +98,7 @@ export default {
ContactLabel,
CustomAttributes,
CustomAttributeSelector,
+ draggable,
},
mixins: [uiSettingsMixin],
props: {
@@ -85,12 +115,30 @@ export default {
default: true,
},
},
+ data() {
+ return {
+ dragEnabled: true,
+ contactSidebarItems: [],
+ dragging: false,
+ };
+ },
computed: {
hasContactAttributes() {
const { custom_attributes: customAttributes } = this.contact;
return customAttributes && Object.keys(customAttributes).length;
},
},
+ mounted() {
+ this.contactSidebarItems = this.contactSidebarItemsOrder;
+ },
+ methods: {
+ onDragEnd() {
+ this.dragging = false;
+ this.updateUISettings({
+ contact_sidebar_items_order: this.contactSidebarItems,
+ });
+ },
+ },
};
diff --git a/app/javascript/dashboard/routes/dashboard/conversation/ContactPanel.vue b/app/javascript/dashboard/routes/dashboard/conversation/ContactPanel.vue
index 3540c9b9f..f5a540834 100644
--- a/app/javascript/dashboard/routes/dashboard/conversation/ContactPanel.vue
+++ b/app/javascript/dashboard/routes/dashboard/conversation/ContactPanel.vue
@@ -4,118 +4,95 @@
-
-
toggleSidebarUIState('is_conv_actions_open', value)"
- >
-
-
-
+
+
+
+
toggleSidebarUIState('is_conv_actions_open', value)
+ "
>
-
-
- {{ $t('CONVERSATION_SIDEBAR.SELF_ASSIGN') }}
-
-
-
-
+
+
-
-
+
- toggleSidebarUIState('is_conv_details_open', value)
"
- :no-search-result="
- $t('AGENT_MGMT.MULTI_SELECTOR.SEARCH.NO_RESULTS.TEAM')
- "
- :input-placeholder="
- $t('AGENT_MGMT.MULTI_SELECTOR.SEARCH.PLACEHOLDER.TEAM')
- "
- @click="onClickAssignTeam"
- />
+ >
+
+
+
+
+
+
+ toggleSidebarUIState('is_contact_attributes_open', value)
+ "
+ >
+
+
+
+
+
+
toggleSidebarUIState('is_previous_conv_open', value)
+ "
+ >
+
+
-
-
-
-
-
toggleSidebarUIState('is_conv_details_open', value)"
- >
-
-
-
-
toggleSidebarUIState('is_contact_attributes_open', value)
- "
- >
-
-
-
-
-
toggleSidebarUIState('is_previous_conv_open', value)"
- >
-
-
+
+
@@ -126,27 +103,25 @@ import agentMixin from '../../../mixins/agentMixin';
import AccordionItem from 'dashboard/components/Accordion/AccordionItem';
import ContactConversations from './ContactConversations.vue';
-import ContactDetailsItem from './ContactDetailsItem.vue';
+import ConversationAction from './ConversationAction.vue';
+
import ContactInfo from './contact/ContactInfo';
import ConversationInfo from './ConversationInfo';
-import ConversationLabels from './labels/LabelBox.vue';
-import MultiselectDropdown from 'shared/components/ui/MultiselectDropdown.vue';
import CustomAttributes from './customAttributes/CustomAttributes.vue';
import CustomAttributeSelector from './customAttributes/CustomAttributeSelector.vue';
-
+import draggable from 'vuedraggable';
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
export default {
components: {
AccordionItem,
ContactConversations,
- ContactDetailsItem,
ContactInfo,
ConversationInfo,
- ConversationLabels,
- MultiselectDropdown,
CustomAttributes,
CustomAttributeSelector,
+ ConversationAction,
+ draggable,
},
mixins: [alertMixin, agentMixin, uiSettingsMixin],
props: {
@@ -163,6 +138,13 @@ export default {
default: () => {},
},
},
+ data() {
+ return {
+ dragEnabled: true,
+ conversationSidebarItems: [],
+ dragging: false,
+ };
+ },
computed: {
...mapGetters({
currentChat: 'getSelectedChat',
@@ -194,61 +176,6 @@ export default {
const { custom_attributes: customAttributes } = this.contact;
return customAttributes && Object.keys(customAttributes).length;
},
- teamsList() {
- if (this.assignedTeam) {
- return [
- {
- id: 0,
- name: 'None',
- },
- ...this.teams,
- ];
- }
- return this.teams;
- },
- assignedAgent: {
- get() {
- return this.currentChat.meta.assignee;
- },
- set(agent) {
- const agentId = agent ? agent.id : 0;
- this.$store.dispatch('setCurrentChatAssignee', agent);
- this.$store
- .dispatch('assignAgent', {
- conversationId: this.currentChat.id,
- agentId,
- })
- .then(() => {
- this.showAlert(this.$t('CONVERSATION.CHANGE_AGENT'));
- });
- },
- },
- assignedTeam: {
- get() {
- return this.currentChat.meta.team;
- },
- set(team) {
- const teamId = team ? team.id : 0;
- this.$store.dispatch('setCurrentChatTeam', team);
- this.$store
- .dispatch('assignTeam', {
- conversationId: this.currentChat.id,
- teamId,
- })
- .then(() => {
- this.showAlert(this.$t('CONVERSATION.CHANGE_TEAM'));
- });
- },
- },
- showSelfAssign() {
- if (!this.assignedAgent) {
- return true;
- }
- if (this.assignedAgent.id !== this.currentUser.id) {
- return true;
- }
- return false;
- },
},
watch: {
conversationId(newConversationId, prevConversationId) {
@@ -261,6 +188,7 @@ export default {
},
},
mounted() {
+ this.conversationSidebarItems = this.conversationSidebarItemsOrder;
this.getContactDetails();
this.$store.dispatch('attributes/get', 0);
},
@@ -281,43 +209,12 @@ export default {
openTranscriptModal() {
this.showTranscriptModal = true;
},
- onSelfAssign() {
- const {
- account_id,
- availability_status,
- available_name,
- email,
- id,
- name,
- role,
- avatar_url,
- } = this.currentUser;
- const selfAssign = {
- account_id,
- availability_status,
- available_name,
- email,
- id,
- name,
- role,
- thumbnail: avatar_url,
- };
- this.assignedAgent = selfAssign;
- },
- onClickAssignAgent(selectedItem) {
- if (this.assignedAgent && this.assignedAgent.id === selectedItem.id) {
- this.assignedAgent = null;
- } else {
- this.assignedAgent = selectedItem;
- }
- },
- onClickAssignTeam(selectedItemTeam) {
- if (this.assignedTeam && this.assignedTeam.id === selectedItemTeam.id) {
- this.assignedTeam = null;
- } else {
- this.assignedTeam = selectedItemTeam;
- }
+ onDragEnd() {
+ this.dragging = false;
+ this.updateUISettings({
+ conversation_sidebar_items_order: this.conversationSidebarItems,
+ });
},
},
};
diff --git a/app/javascript/dashboard/routes/dashboard/conversation/ConversationAction.vue b/app/javascript/dashboard/routes/dashboard/conversation/ConversationAction.vue
new file mode 100644
index 000000000..940e1d1b0
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/conversation/ConversationAction.vue
@@ -0,0 +1,189 @@
+
+
+
+
+
+
+ {{ $t('CONVERSATION_SIDEBAR.SELF_ASSIGN') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/package.json b/package.json
index b54d995f5..d74e1f537 100644
--- a/package.json
+++ b/package.json
@@ -65,6 +65,7 @@
"vue-template-compiler": "2.6.12",
"vue-upload-component": "2.8.22",
"vue2-datepicker": "^3.9.1",
+ "vuedraggable": "^2.24.3",
"vuelidate": "0.7.6",
"vuex": "~2.1.1",
"vuex-router-sync": "~4.1.2"
diff --git a/yarn.lock b/yarn.lock
index 04287bddb..aa0ae5567 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -13540,6 +13540,11 @@ sort-keys@^1.0.0:
dependencies:
is-plain-obj "^1.0.0"
+sortablejs@1.10.2:
+ version "1.10.2"
+ resolved "https://registry.npmjs.org/sortablejs/-/sortablejs-1.10.2.tgz#6e40364d913f98b85a14f6678f92b5c1221f5290"
+ integrity sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A==
+
source-list-map@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
@@ -15112,6 +15117,13 @@ vue@2.6.12, vue@^2.6.12:
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.12.tgz#f5ebd4fa6bd2869403e29a896aed4904456c9123"
integrity sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg==
+vuedraggable@^2.24.3:
+ version "2.24.3"
+ resolved "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.24.3.tgz#43c93849b746a24ce503e123d5b259c701ba0d19"
+ integrity sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g==
+ dependencies:
+ sortablejs "1.10.2"
+
vuelidate@0.7.6:
version "0.7.6"
resolved "https://registry.yarnpkg.com/vuelidate/-/vuelidate-0.7.6.tgz#84100c13b943470660d0416642845cd2a1edf4b2"