feat: Add assign team option to the context menu (#5153)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
@@ -121,6 +121,7 @@
|
||||
@select-conversation="selectConversation"
|
||||
@de-select-conversation="deSelectConversation"
|
||||
@assign-agent="onAssignAgent"
|
||||
@assign-team="onAssignTeam"
|
||||
@assign-label="onAssignLabels"
|
||||
@update-conversation-status="toggleConversationStatus"
|
||||
@context-menu-toggle="onContextMenuToggle"
|
||||
@@ -618,11 +619,44 @@ export default {
|
||||
},
|
||||
});
|
||||
this.selectedConversations = [];
|
||||
this.showAlert(this.$t('BULK_ACTION.ASSIGN_SUCCESFUL'));
|
||||
if (conversationId) {
|
||||
this.showAlert(
|
||||
this.$t(
|
||||
'CONVERSATION.CARD_CONTEXT_MENU.API.AGENT_ASSIGNMENT.SUCCESFUL',
|
||||
{
|
||||
agentName: agent.name,
|
||||
conversationId,
|
||||
}
|
||||
)
|
||||
);
|
||||
} else {
|
||||
this.showAlert(this.$t('BULK_ACTION.ASSIGN_SUCCESFUL'));
|
||||
}
|
||||
} catch (err) {
|
||||
this.showAlert(this.$t('BULK_ACTION.ASSIGN_FAILED'));
|
||||
}
|
||||
},
|
||||
async onAssignTeam(team, conversationId = null) {
|
||||
try {
|
||||
await this.$store.dispatch('assignTeam', {
|
||||
conversationId,
|
||||
teamId: team.id,
|
||||
});
|
||||
this.showAlert(
|
||||
this.$t(
|
||||
'CONVERSATION.CARD_CONTEXT_MENU.API.TEAM_ASSIGNMENT.SUCCESFUL',
|
||||
{
|
||||
team: team.name,
|
||||
conversationId,
|
||||
}
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
this.showAlert(
|
||||
this.$t('CONVERSATION.CARD_CONTEXT_MENU.API.TEAM_ASSIGNMENT.FAILED')
|
||||
);
|
||||
}
|
||||
},
|
||||
// Same method used in context menu, conversationId being passed from there.
|
||||
async onAssignLabels(labels, conversationId = null) {
|
||||
try {
|
||||
@@ -634,7 +668,19 @@ export default {
|
||||
},
|
||||
});
|
||||
this.selectedConversations = [];
|
||||
this.showAlert(this.$t('BULK_ACTION.LABELS.ASSIGN_SUCCESFUL'));
|
||||
if (conversationId) {
|
||||
this.showAlert(
|
||||
this.$t(
|
||||
'CONVERSATION.CARD_CONTEXT_MENU.API.LABEL_ASSIGNMENT.SUCCESFUL',
|
||||
{
|
||||
labelName: labels[0],
|
||||
conversationId,
|
||||
}
|
||||
)
|
||||
);
|
||||
} else {
|
||||
this.showAlert(this.$t('BULK_ACTION.LABELS.ASSIGN_SUCCESFUL'));
|
||||
}
|
||||
} catch (err) {
|
||||
this.showAlert(this.$t('BULK_ACTION.LABELS.ASSIGN_FAILED'));
|
||||
}
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
@update-conversation="onUpdateConversation"
|
||||
@assign-agent="onAssignAgent"
|
||||
@assign-label="onAssignLabel"
|
||||
@assign-team="onAssignTeam"
|
||||
/>
|
||||
</woot-context-menu>
|
||||
</div>
|
||||
@@ -352,6 +353,10 @@ export default {
|
||||
this.$emit('assign-label', [label.title], [this.chat.id]);
|
||||
this.closeContextMenu();
|
||||
},
|
||||
async onAssignTeam(team) {
|
||||
this.$emit('assign-team', team, this.chat.id);
|
||||
this.closeContextMenu();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
:key="option.key"
|
||||
:option="option"
|
||||
variant="icon"
|
||||
@click.native="toggleStatus(option.key, null)"
|
||||
@click="toggleStatus(option.key, null)"
|
||||
/>
|
||||
</template>
|
||||
<menu-item-with-submenu :option="snoozeMenuConfig">
|
||||
@@ -14,7 +14,7 @@
|
||||
v-for="(option, i) in snoozeMenuConfig.options"
|
||||
:key="i"
|
||||
:option="option"
|
||||
@click.native="snoozeConversation(option.snoozedUntil)"
|
||||
@click="snoozeConversation(option.snoozedUntil)"
|
||||
/>
|
||||
</menu-item-with-submenu>
|
||||
<menu-item-with-submenu :option="labelMenuConfig">
|
||||
@@ -24,7 +24,7 @@
|
||||
:key="label.id"
|
||||
:option="generateMenuLabelConfig(label, 'label')"
|
||||
variant="label"
|
||||
@click.native="$emit('assign-label', label)"
|
||||
@click="$emit('assign-label', label)"
|
||||
/>
|
||||
</template>
|
||||
</menu-item-with-submenu>
|
||||
@@ -36,10 +36,18 @@
|
||||
:key="agent.id"
|
||||
:option="generateMenuLabelConfig(agent, 'agent')"
|
||||
variant="agent"
|
||||
@click.native="$emit('assign-agent', agent)"
|
||||
@click="$emit('assign-agent', agent)"
|
||||
/>
|
||||
</template>
|
||||
</menu-item-with-submenu>
|
||||
<menu-item-with-submenu :option="teamMenuConfig">
|
||||
<menu-item
|
||||
v-for="team in teams"
|
||||
:key="team.id"
|
||||
:option="generateMenuLabelConfig(team, 'team')"
|
||||
@click="$emit('assign-team', team)"
|
||||
/>
|
||||
</menu-item-with-submenu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -119,11 +127,17 @@ export default {
|
||||
icon: 'person-add',
|
||||
label: this.$t('CONVERSATION.CARD_CONTEXT_MENU.ASSIGN_AGENT'),
|
||||
},
|
||||
teamMenuConfig: {
|
||||
key: 'team',
|
||||
icon: 'people-team-add',
|
||||
label: this.$t('CONVERSATION.CARD_CONTEXT_MENU.ASSIGN_TEAM'),
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
labels: 'labels/getLabels',
|
||||
teams: 'teams/getTeams',
|
||||
assignableAgentsUiFlags: 'inboxAssignableAgents/getUIFlags',
|
||||
}),
|
||||
assignableAgents() {
|
||||
@@ -160,6 +174,7 @@ export default {
|
||||
...(type === 'text' && { label: option.label }),
|
||||
...(type === 'label' && { label: option.title }),
|
||||
...(type === 'agent' && { label: option.name }),
|
||||
...(type === 'team' && { label: option.name }),
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="menu">
|
||||
<div class="menu" @click.stop="$emit('click')">
|
||||
<fluent-icon
|
||||
v-if="variant === 'icon' && option.icon"
|
||||
:icon="option.icon"
|
||||
@@ -18,7 +18,7 @@
|
||||
size="20px"
|
||||
class="agent-thumbnail"
|
||||
/>
|
||||
<p class="menu-label">{{ option.label }}</p>
|
||||
<p class="menu-label truncate-text">{{ option.label }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -45,14 +45,16 @@ export default {
|
||||
.menu {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
flex-wrap: nowrap;
|
||||
width: calc(var(--space-mega) * 2);
|
||||
padding: var(--space-smaller);
|
||||
border-radius: var(--border-radius-small);
|
||||
min-width: calc(var(--space-mega) * 2);
|
||||
overflow: hidden;
|
||||
|
||||
.menu-label {
|
||||
margin: 0;
|
||||
font-size: var(--font-size-mini);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
|
||||
@@ -72,7 +72,22 @@
|
||||
},
|
||||
"ASSIGN_AGENT": "Assign agent",
|
||||
"ASSIGN_LABEL": "Assign label",
|
||||
"AGENTS_LOADING": "Loading agents..."
|
||||
"AGENTS_LOADING": "Loading agents...",
|
||||
"ASSIGN_TEAM": "Assign team",
|
||||
"API": {
|
||||
"AGENT_ASSIGNMENT": {
|
||||
"SUCCESFUL": "Conversation id %{conversationId} assigned to \"%{agentName}\"",
|
||||
"FAILED": "Couldn't assign agent. Please try again."
|
||||
},
|
||||
"LABEL_ASSIGNMENT": {
|
||||
"SUCCESFUL": "Assigned label #%{labelName} to conversation id %{conversationId}",
|
||||
"FAILED": "Couldn't assign label. Please try again."
|
||||
},
|
||||
"TEAM_ASSIGNMENT": {
|
||||
"SUCCESFUL": "Assigned team \"%{team}\" to conversation id %{conversationId}",
|
||||
"FAILED": "Couldn't assign team. Please try again."
|
||||
}
|
||||
}
|
||||
},
|
||||
"FOOTER": {
|
||||
"MESSAGE_SIGN_TOOLTIP": "Message signature",
|
||||
|
||||
@@ -111,13 +111,11 @@ export default {
|
||||
return this.currentChat.meta.team;
|
||||
},
|
||||
set(team) {
|
||||
const conversationId = this.currentChat.id;
|
||||
const teamId = team ? team.id : 0;
|
||||
this.$store.dispatch('setCurrentChatTeam', team);
|
||||
this.$store.dispatch('setCurrentChatTeam', { team, conversationId });
|
||||
this.$store
|
||||
.dispatch('assignTeam', {
|
||||
conversationId: this.currentChat.id,
|
||||
teamId,
|
||||
})
|
||||
.dispatch('assignTeam', { conversationId, teamId })
|
||||
.then(() => {
|
||||
this.showAlert(this.$t('CONVERSATION.CHANGE_TEAM'));
|
||||
});
|
||||
|
||||
@@ -121,14 +121,14 @@ const actions = {
|
||||
conversationId,
|
||||
teamId,
|
||||
});
|
||||
dispatch('setCurrentChatTeam', response.data);
|
||||
dispatch('setCurrentChatTeam', { team: response.data, conversationId });
|
||||
} catch (error) {
|
||||
// Handle error
|
||||
}
|
||||
},
|
||||
|
||||
setCurrentChatTeam({ commit }, team) {
|
||||
commit(types.ASSIGN_TEAM, team);
|
||||
setCurrentChatTeam({ commit }, { team, conversationId }) {
|
||||
commit(types.ASSIGN_TEAM, { team, conversationId });
|
||||
},
|
||||
|
||||
toggleStatus: async (
|
||||
|
||||
@@ -68,8 +68,8 @@ export const mutations = {
|
||||
Vue.set(chat.meta, 'assignee', assignee);
|
||||
},
|
||||
|
||||
[types.ASSIGN_TEAM](_state, team) {
|
||||
const [chat] = getSelectedChatConversation(_state);
|
||||
[types.ASSIGN_TEAM](_state, { team, conversationId }) {
|
||||
const [chat] = _state.allConversations.filter(c => c.id === conversationId);
|
||||
Vue.set(chat.meta, 'team', team);
|
||||
},
|
||||
|
||||
|
||||
@@ -327,10 +327,13 @@ describe('#actions', () => {
|
||||
axios.post.mockResolvedValue({
|
||||
data: { id: 1, name: 'Team' },
|
||||
});
|
||||
await actions.setCurrentChatTeam({ commit }, { id: 1, name: 'Team' });
|
||||
await actions.setCurrentChatTeam(
|
||||
{ commit },
|
||||
{ team: { id: 1, name: 'Team' }, conversationId: 1 }
|
||||
);
|
||||
expect(commit).toHaveBeenCalledTimes(1);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
['ASSIGN_TEAM', { id: 1, name: 'Team' }],
|
||||
['ASSIGN_TEAM', { team: { id: 1, name: 'Team' }, conversationId: 1 }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -37,6 +37,19 @@ describe('#mutations', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#ASSIGN_TEAM', () => {
|
||||
it('clears current chat window', () => {
|
||||
const state = { allConversations: [{ id: 1, meta: {} }] };
|
||||
mutations[types.ASSIGN_TEAM](state, {
|
||||
team: { id: 1, name: 'Team 1' },
|
||||
conversationId: 1,
|
||||
});
|
||||
expect(state.allConversations).toEqual([
|
||||
{ id: 1, meta: { team: { id: 1, name: 'Team 1' } } },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#SET_CURRENT_CHAT_WINDOW', () => {
|
||||
it('set current chat window', () => {
|
||||
const state = { selectedChatId: 1 };
|
||||
|
||||
Reference in New Issue
Block a user