diff --git a/app/javascript/dashboard/api/inbox/conversation.js b/app/javascript/dashboard/api/inbox/conversation.js
index 159e77f0e..b520156a4 100644
--- a/app/javascript/dashboard/api/inbox/conversation.js
+++ b/app/javascript/dashboard/api/inbox/conversation.js
@@ -33,12 +33,17 @@ class ConversationApi extends ApiClient {
}
assignAgent({ conversationId, agentId }) {
- axios.post(
+ return axios.post(
`${this.url}/${conversationId}/assignments?assignee_id=${agentId}`,
{}
);
}
+ assignTeam({ conversationId, teamId }) {
+ const params = { team_id: teamId };
+ return axios.post(`${this.url}/${conversationId}/assignments`, params);
+ }
+
markMessageRead({ id }) {
return axios.post(`${this.url}/${id}/update_last_seen`);
}
diff --git a/app/javascript/dashboard/api/specs/inbox/conversation.spec.js b/app/javascript/dashboard/api/specs/inbox/conversation.spec.js
index 31be5e87e..6d4cdeec4 100644
--- a/app/javascript/dashboard/api/specs/inbox/conversation.spec.js
+++ b/app/javascript/dashboard/api/specs/inbox/conversation.spec.js
@@ -11,6 +11,7 @@ describe('#ConversationAPI', () => {
expect(conversationAPI).toHaveProperty('delete');
expect(conversationAPI).toHaveProperty('toggleStatus');
expect(conversationAPI).toHaveProperty('assignAgent');
+ expect(conversationAPI).toHaveProperty('assignTeam');
expect(conversationAPI).toHaveProperty('markMessageRead');
expect(conversationAPI).toHaveProperty('toggleTyping');
expect(conversationAPI).toHaveProperty('mute');
diff --git a/app/javascript/dashboard/assets/scss/plugins/_multiselect.scss b/app/javascript/dashboard/assets/scss/plugins/_multiselect.scss
index b7a27dff6..36df6af14 100644
--- a/app/javascript/dashboard/assets/scss/plugins/_multiselect.scss
+++ b/app/javascript/dashboard/assets/scss/plugins/_multiselect.scss
@@ -16,7 +16,7 @@
margin-bottom: var(--space-normal);
.multiselect--active {
- > .multiselect__tags {
+ >.multiselect__tags {
border-color: $color-woot;
}
}
@@ -124,6 +124,7 @@
}
.sidebar-labels-wrap {
+
&.has-edited,
&:hover {
.multiselect {
@@ -132,16 +133,48 @@
}
.multiselect {
- > .multiselect__select {
+ >.multiselect__select {
visibility: hidden;
}
- > .multiselect__tags {
+ >.multiselect__tags {
border-color: transparent;
}
- &.multiselect--active > .multiselect__tags {
+ &.multiselect--active>.multiselect__tags {
border-color: $color-woot;
}
}
}
+
+
+.multiselect-wrap--small {
+ $multiselect-height: 3.8rem;
+
+ .multiselect__tags,
+ .multiselect__input,
+ .multiselect {
+ background: var(--white);
+ font-size: var(--font-size-small);
+ height: $multiselect-height;
+ min-height: $multiselect-height;
+ }
+
+ .multiselect__input {
+ height: $multiselect-height - $space-micro;
+ min-height: $multiselect-height - $space-micro;
+ }
+
+ .multiselect__single {
+ font-size: var(--font-size-small);
+ padding: var(--space-small) 0;
+ }
+
+ .multiselect__placeholder {
+ padding: var(--space-small) 0;
+ }
+
+ .multiselect__select {
+ min-height: $multiselect-height;
+ }
+}
diff --git a/app/javascript/dashboard/i18n/locale/en/conversation.json b/app/javascript/dashboard/i18n/locale/en/conversation.json
index bf7c4550a..4fccad865 100644
--- a/app/javascript/dashboard/i18n/locale/en/conversation.json
+++ b/app/javascript/dashboard/i18n/locale/en/conversation.json
@@ -51,6 +51,7 @@
"VISIBLE_TO_AGENTS": "Private Note: Only visible to you and your team",
"CHANGE_STATUS": "Conversation status changed",
"CHANGE_AGENT": "Conversation Assignee changed",
+ "CHANGE_TEAM": "Conversation team changed",
"SENT_BY": "Sent by:",
"ASSIGNMENT": {
"SELECT_AGENT": "Select Agent",
@@ -98,5 +99,14 @@
"DESCRIPTION": "Labels provide an easier way to categorize your conversation. Create some labels like #support-enquiry, #billing-question etc., so that you can use them in a conversation later.",
"NEW_LINK": "Click here to create tags"
}
+ },
+ "CONVERSATION_SIDEBAR": {
+ "DETAILS_TITLE": "Conversations Details",
+ "ASSIGNEE_LABEL": "Assigned Agent",
+ "TEAM_LABEL": "Assigned Team",
+ "SELECT": {
+ "PLACEHOLDER": "None"
+ }
}
+
}
diff --git a/app/javascript/dashboard/routes/dashboard/conversation/ContactPanel.vue b/app/javascript/dashboard/routes/dashboard/conversation/ContactPanel.vue
index ccf65f329..9939b80dd 100644
--- a/app/javascript/dashboard/routes/dashboard/conversation/ContactPanel.vue
+++ b/app/javascript/dashboard/routes/dashboard/conversation/ContactPanel.vue
@@ -4,6 +4,43 @@
+
+
+ {{ $t('CONVERSATION_SIDEBAR.DETAILS_TITLE') }}
+
+
+
+
+
+
+
+
+
+
import { mapGetters } from 'vuex';
+import alertMixin from 'shared/mixins/alertMixin';
import ContactConversations from './ContactConversations.vue';
import ContactDetailsItem from './ContactDetailsItem.vue';
@@ -83,6 +121,7 @@ export default {
ContactInfo,
ConversationLabels,
},
+ mixins: [alertMixin],
props: {
conversationId: {
type: [Number, String],
@@ -96,6 +135,8 @@ export default {
computed: {
...mapGetters({
currentChat: 'getSelectedChat',
+ agents: 'agents/getVerifiedAgents',
+ teams: 'teams/getTeams',
}),
currentConversationMetaData() {
return this.$store.getters[
@@ -159,6 +200,46 @@ export default {
contact() {
return this.$store.getters['contacts/getContact'](this.contactId);
},
+ agentsList() {
+ return [{ id: 0, name: 'None' }, ...this.agents];
+ },
+ teamsList() {
+ return [{ id: 0, name: 'None' }, ...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'));
+ });
+ },
+ },
},
watch: {
conversationId(newConversationId, prevConversationId) {
@@ -191,12 +272,10 @@ export default {
diff --git a/app/javascript/dashboard/store/modules/conversations/actions.js b/app/javascript/dashboard/store/modules/conversations/actions.js
index 88ca6d710..8e4e20954 100644
--- a/app/javascript/dashboard/store/modules/conversations/actions.js
+++ b/app/javascript/dashboard/store/modules/conversations/actions.js
@@ -103,18 +103,38 @@ const actions = {
}
},
- assignAgent: async ({ commit }, { conversationId, agentId }) => {
+ assignAgent: async ({ dispatch }, { conversationId, agentId }) => {
try {
const response = await ConversationApi.assignAgent({
conversationId,
agentId,
});
- commit(types.default.ASSIGN_AGENT, response.data);
+ dispatch('setCurrentChatAssignee', response.data);
} catch (error) {
// Handle error
}
},
+ setCurrentChatAssignee({ commit }, assignee) {
+ commit(types.default.ASSIGN_AGENT, assignee);
+ },
+
+ assignTeam: async ({ dispatch }, { conversationId, teamId }) => {
+ try {
+ const response = await ConversationApi.assignTeam({
+ conversationId,
+ teamId,
+ });
+ dispatch('setCurrentChatTeam', response.data);
+ } catch (error) {
+ // Handle error
+ }
+ },
+
+ setCurrentChatTeam({ commit }, team) {
+ commit(types.default.ASSIGN_TEAM, team);
+ },
+
toggleStatus: async ({ commit }, data) => {
try {
const response = await ConversationApi.toggleStatus(data);
diff --git a/app/javascript/dashboard/store/modules/conversations/index.js b/app/javascript/dashboard/store/modules/conversations/index.js
index ae9945bf3..d9721b4fc 100644
--- a/app/javascript/dashboard/store/modules/conversations/index.js
+++ b/app/javascript/dashboard/store/modules/conversations/index.js
@@ -61,7 +61,12 @@ export const mutations = {
[types.default.ASSIGN_AGENT](_state, assignee) {
const [chat] = getSelectedChatConversation(_state);
- chat.meta.assignee = assignee;
+ Vue.set(chat.meta, 'assignee', assignee);
+ },
+
+ [types.default.ASSIGN_TEAM](_state, team) {
+ const [chat] = getSelectedChatConversation(_state);
+ Vue.set(chat.meta, 'team', team);
},
[types.default.RESOLVE_CONVERSATION](_state, status) {
@@ -145,7 +150,7 @@ export const mutations = {
// Update assignee on action cable message
[types.default.UPDATE_ASSIGNEE](_state, payload) {
const [chat] = _state.allConversations.filter(c => c.id === payload.id);
- chat.meta.assignee = payload.assignee;
+ Vue.set(chat.meta, 'assignee', payload.assignee);
},
[types.default.UPDATE_CONVERSATION_CONTACT](
diff --git a/app/javascript/dashboard/store/modules/specs/conversations/actions.spec.js b/app/javascript/dashboard/store/modules/specs/conversations/actions.spec.js
index 666f5fa4b..a4e59f5c3 100644
--- a/app/javascript/dashboard/store/modules/specs/conversations/actions.spec.js
+++ b/app/javascript/dashboard/store/modules/specs/conversations/actions.spec.js
@@ -189,4 +189,52 @@ describe('#actions', () => {
expect(commit.mock.calls).toEqual([]);
});
});
+
+ describe('#assignAgent', () => {
+ it('sends correct mutations if assignment is successful', async () => {
+ axios.post.mockResolvedValue({
+ data: { id: 1, name: 'User' },
+ });
+ await actions.assignAgent({ commit }, { conversationId: 1, agentId: 1 });
+ expect(commit).toHaveBeenCalledTimes(0);
+ expect(commit.mock.calls).toEqual([]);
+ });
+ });
+
+ describe('#setCurrentChatAssignee', () => {
+ it('sends correct mutations if assignment is successful', async () => {
+ axios.post.mockResolvedValue({
+ data: { id: 1, name: 'User' },
+ });
+ await actions.setCurrentChatAssignee({ commit }, { id: 1, name: 'User' });
+ expect(commit).toHaveBeenCalledTimes(1);
+ expect(commit.mock.calls).toEqual([
+ ['ASSIGN_AGENT', { id: 1, name: 'User' }],
+ ]);
+ });
+ });
+
+ describe('#assignTeam', () => {
+ it('sends correct mutations if assignment is successful', async () => {
+ axios.post.mockResolvedValue({
+ data: { id: 1, name: 'Team' },
+ });
+ await actions.assignTeam({ commit }, { conversationId: 1, teamId: 1 });
+ expect(commit).toHaveBeenCalledTimes(0);
+ expect(commit.mock.calls).toEqual([]);
+ });
+ });
+
+ describe('#setCurrentChatTeam', () => {
+ it('sends correct mutations if assignment is successful', async () => {
+ axios.post.mockResolvedValue({
+ data: { id: 1, name: 'Team' },
+ });
+ await actions.setCurrentChatTeam({ commit }, { id: 1, name: 'Team' });
+ expect(commit).toHaveBeenCalledTimes(1);
+ expect(commit.mock.calls).toEqual([
+ ['ASSIGN_TEAM', { id: 1, name: 'Team' }],
+ ]);
+ });
+ });
});
diff --git a/app/javascript/dashboard/store/mutation-types.js b/app/javascript/dashboard/store/mutation-types.js
index 433c4c6b0..355058cba 100755
--- a/app/javascript/dashboard/store/mutation-types.js
+++ b/app/javascript/dashboard/store/mutation-types.js
@@ -28,6 +28,7 @@ export default {
MUTE_CONVERSATION: 'MUTE_CONVERSATION',
UNMUTE_CONVERSATION: 'UNMUTE_CONVERSATION',
ASSIGN_AGENT: 'ASSIGN_AGENT',
+ ASSIGN_TEAM: 'ASSIGN_TEAM',
SET_CHAT_META: 'SET_CHAT_META',
ADD_MESSAGE: 'ADD_MESSAGE',
ADD_PENDING_MESSAGE: 'ADD_PENDING_MESSAGE',
diff --git a/app/views/api/v1/conversations/partials/_conversation.json.jbuilder b/app/views/api/v1/conversations/partials/_conversation.json.jbuilder
index 50afe3b44..12879b3d5 100644
--- a/app/views/api/v1/conversations/partials/_conversation.json.jbuilder
+++ b/app/views/api/v1/conversations/partials/_conversation.json.jbuilder
@@ -8,6 +8,11 @@ json.meta do
json.partial! 'api/v1/models/agent.json.jbuilder', resource: conversation.assignee
end
end
+ if conversation.team.present?
+ json.team do
+ json.partial! 'api/v1/models/team.json.jbuilder', resource: conversation.team
+ end
+ end
end
json.id conversation.display_id