feat: Add assign team option to the context menu (#5153)

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
Fayaz Ahmed
2022-08-05 10:57:58 +05:30
committed by GitHub
parent 9bea84e2b5
commit fc9699d993
11 changed files with 121 additions and 23 deletions

View File

@@ -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'));
}

View File

@@ -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>

View File

@@ -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 }),
};
},
},

View File

@@ -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 {

View File

@@ -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",

View File

@@ -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'));
});

View File

@@ -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 (

View File

@@ -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);
},

View File

@@ -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 }],
]);
});
});

View File

@@ -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 };