feat: Rewrite agentMixin to a helper (#9940)

# Pull Request Template

## Description

This PR will replace the usage of `agentMixin`with the utility helpers
functions.

**Files updated**

1. dashboard/components/widgets/conversation/contextMenu/Index.vue
2. dashboard/components/widgets/conversation/ConversationHeader.vue
**(Not used)**
3. dashboard/routes/dashboard/commands/commandbar.vue
4. dashboard/routes/dashboard/conversation/ConversationAction.vue
5. dashboard/routes/dashboard/conversation/ConversationParticipant.vue

Fixes
https://linear.app/chatwoot/issue/CW-3442/rewrite-agentmixin-mixin-to-a-composable

## Type of change

- [x] New feature (non-breaking change which adds functionality)

## How Has This Been Tested?

**Test cases**

1. See agent list sorting based on availability, if agents are on the
same status, then sorted by name.
2. Test actions like assigning/unassigning agent from conversation
sidebar, CMD bar, Context menu.
3. Test actions like adding/removing participants from conversation
sidebar.
4. See agent list is generated properly, none value.


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
This commit is contained in:
Sivin Varghese
2024-08-22 13:02:11 +05:30
committed by GitHub
parent 429d281501
commit c63a6ed8ec
14 changed files with 643 additions and 482 deletions

View File

@@ -1,69 +0,0 @@
import { mapGetters } from 'vuex';
export default {
computed: {
...mapGetters({
currentUser: 'getCurrentUser',
currentAccountId: 'getCurrentAccountId',
}),
assignableAgents() {
return this.$store.getters['inboxAssignableAgents/getAssignableAgents'](
this.inboxId
);
},
isAgentSelected() {
return this.currentChat?.meta?.assignee;
},
createNoneAgent() {
return {
confirmed: true,
name: 'None',
id: 0,
role: 'agent',
account_id: 0,
email: 'None',
};
},
agentsList() {
const agents = this.assignableAgents || [];
const agentsByUpdatedPresence = this.getAgentsByUpdatedPresence(agents);
const none = this.createNoneAgent;
const filteredAgentsByAvailability = this.sortedAgentsByAvailability(
agentsByUpdatedPresence
);
const filteredAgents = [
...(this.isAgentSelected ? [none] : []),
...filteredAgentsByAvailability,
];
return filteredAgents;
},
},
methods: {
getAgentsByAvailability(agents, availability) {
return agents
.filter(agent => agent.availability_status === availability)
.sort((a, b) => a.name.localeCompare(b.name));
},
sortedAgentsByAvailability(agents) {
const onlineAgents = this.getAgentsByAvailability(agents, 'online');
const busyAgents = this.getAgentsByAvailability(agents, 'busy');
const offlineAgents = this.getAgentsByAvailability(agents, 'offline');
const filteredAgents = [...onlineAgents, ...busyAgents, ...offlineAgents];
return filteredAgents;
},
getAgentsByUpdatedPresence(agents) {
// Here we are updating the availability status of the current user dynamically (live) based on the current account availability status
const agentsWithDynamicPresenceUpdate = agents.map(item =>
item.id === this.currentUser.id
? {
...item,
availability_status: this.currentUser.accounts.find(
account => account.id === this.currentAccountId
).availability_status,
}
: item
);
return agentsWithDynamicPresenceUpdate;
},
},
};

View File

@@ -1,246 +0,0 @@
export default {
allAgents: [
{
account_id: 1,
availability_status: 'online',
available_name: 'John K',
confirmed: true,
email: 'john@chatwoot.com',
id: 1,
name: 'John Kennady',
role: 'administrator',
},
{
account_id: 1,
availability_status: 'busy',
available_name: 'Samuel K',
confirmed: true,
email: 'samuel@chatwoot.com',
id: 2,
name: 'Samuel Keta',
role: 'agent',
},
{
account_id: 1,
availability_status: 'offline',
available_name: 'James K',
confirmed: true,
email: 'james@chatwoot.com',
id: 3,
name: 'James Koti',
role: 'agent',
},
{
account_id: 1,
availability_status: 'busy',
available_name: 'Honey',
confirmed: true,
email: 'bee@chatwoot.com',
id: 4,
name: 'Honey Bee',
role: 'agent',
},
{
account_id: 1,
availability_status: 'online',
available_name: 'Abraham',
confirmed: true,
email: 'abraham@chatwoot.com',
id: 5,
name: 'Abraham Keta',
role: 'agent',
},
],
formattedAgents: [
{
account_id: 0,
confirmed: true,
email: 'None',
id: 0,
name: 'None',
role: 'agent',
},
{
account_id: 1,
availability_status: 'online',
available_name: 'Abraham',
confirmed: true,
email: 'abraham@chatwoot.com',
id: 5,
name: 'Abraham Keta',
role: 'agent',
},
{
account_id: 1,
availability_status: 'online',
available_name: 'John K',
confirmed: true,
email: 'john@chatwoot.com',
id: 1,
name: 'John Kennady',
role: 'administrator',
},
{
account_id: 1,
availability_status: 'busy',
available_name: 'Honey',
confirmed: true,
email: 'bee@chatwoot.com',
id: 4,
name: 'Honey Bee',
role: 'agent',
},
{
account_id: 1,
availability_status: 'busy',
available_name: 'Samuel K',
confirmed: true,
email: 'samuel@chatwoot.com',
id: 2,
name: 'Samuel Keta',
role: 'agent',
},
{
account_id: 1,
availability_status: 'offline',
available_name: 'James K',
confirmed: true,
email: 'james@chatwoot.com',
id: 3,
name: 'James Koti',
role: 'agent',
},
],
onlineAgents: [
{
account_id: 1,
availability_status: 'online',
available_name: 'Abraham',
confirmed: true,
email: 'abraham@chatwoot.com',
id: 5,
name: 'Abraham Keta',
role: 'agent',
},
{
account_id: 1,
availability_status: 'online',
available_name: 'John K',
confirmed: true,
email: 'john@chatwoot.com',
id: 1,
name: 'John Kennady',
role: 'administrator',
},
],
busyAgents: [
{
account_id: 1,
availability_status: 'busy',
available_name: 'Honey',
confirmed: true,
email: 'bee@chatwoot.com',
id: 4,
name: 'Honey Bee',
role: 'agent',
},
{
account_id: 1,
availability_status: 'busy',
available_name: 'Samuel K',
confirmed: true,
email: 'samuel@chatwoot.com',
id: 2,
name: 'Samuel Keta',
role: 'agent',
},
],
offlineAgents: [
{
account_id: 1,
availability_status: 'offline',
available_name: 'James K',
confirmed: true,
email: 'james@chatwoot.com',
id: 3,
name: 'James Koti',
role: 'agent',
},
],
sortedByAvailability: [
{
account_id: 1,
availability_status: 'online',
available_name: 'Abraham',
confirmed: true,
email: 'abraham@chatwoot.com',
id: 5,
name: 'Abraham Keta',
role: 'agent',
},
{
account_id: 1,
availability_status: 'online',
available_name: 'John K',
confirmed: true,
email: 'john@chatwoot.com',
id: 1,
name: 'John Kennady',
role: 'administrator',
},
{
account_id: 1,
availability_status: 'busy',
available_name: 'Honey',
confirmed: true,
email: 'bee@chatwoot.com',
id: 4,
name: 'Honey Bee',
role: 'agent',
},
{
account_id: 1,
availability_status: 'busy',
available_name: 'Samuel K',
confirmed: true,
email: 'samuel@chatwoot.com',
id: 2,
name: 'Samuel Keta',
role: 'agent',
},
{
account_id: 1,
availability_status: 'offline',
available_name: 'James K',
confirmed: true,
email: 'james@chatwoot.com',
id: 3,
name: 'James Koti',
role: 'agent',
},
],
formattedAgentsByPresenceOnline: [
{
account_id: 1,
availability_status: 'online',
available_name: 'Abraham',
confirmed: true,
email: 'abr@chatwoot.com',
id: 1,
name: 'Abraham Keta',
role: 'agent',
},
],
formattedAgentsByPresenceOffline: [
{
account_id: 1,
availability_status: 'offline',
available_name: 'Abraham',
confirmed: true,
email: 'abr@chatwoot.com',
id: 1,
name: 'Abraham Keta',
role: 'agent',
},
],
};

View File

@@ -1,140 +0,0 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import agentMixin from '../agentMixin';
import agentFixtures from './agentFixtures';
import Vuex from 'vuex';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('agentMixin', () => {
let getters;
let store;
beforeEach(() => {
getters = {
getCurrentUser: () => ({
id: 1,
accounts: [
{
id: 1,
availability_status: 'online',
auto_offline: false,
},
],
}),
getCurrentAccountId: () => 1,
};
store = new Vuex.Store({ getters });
});
it('return agents by availability', () => {
const Component = {
render() {},
title: 'TestComponent',
mixins: [agentMixin],
data() {
return {
inboxId: 1,
currentChat: { meta: { assignee: { name: 'John' } } },
};
},
computed: {
assignableAgents() {
return agentFixtures.allAgents;
},
},
};
const wrapper = shallowMount(Component, { store, localVue });
expect(
wrapper.vm.getAgentsByAvailability(agentFixtures.allAgents, 'online')
).toEqual(agentFixtures.onlineAgents);
expect(
wrapper.vm.getAgentsByAvailability(agentFixtures.allAgents, 'busy')
).toEqual(agentFixtures.busyAgents);
expect(
wrapper.vm.getAgentsByAvailability(agentFixtures.allAgents, 'offline')
).toEqual(agentFixtures.offlineAgents);
});
it('return sorted agents by availability', () => {
const Component = {
render() {},
title: 'TestComponent',
mixins: [agentMixin],
data() {
return {
inboxId: 1,
currentChat: { meta: { assignee: { name: 'John' } } },
};
},
computed: {
assignableAgents() {
return agentFixtures.allAgents;
},
},
};
const wrapper = shallowMount(Component, { store, localVue });
expect(
wrapper.vm.sortedAgentsByAvailability(agentFixtures.allAgents)
).toEqual(agentFixtures.sortedByAvailability);
});
it('return formatted agents', () => {
const Component = {
render() {},
title: 'TestComponent',
mixins: [agentMixin],
data() {
return {
inboxId: 1,
currentChat: { meta: { assignee: { name: 'John' } } },
};
},
computed: {
assignableAgents() {
return agentFixtures.allAgents;
},
},
};
const wrapper = shallowMount(Component, { store, localVue });
expect(wrapper.vm.agentsList).toEqual(agentFixtures.formattedAgents);
});
it('return formatted agents by presence', () => {
const Component = {
render() {},
title: 'TestComponent',
mixins: [agentMixin],
data() {
return {
inboxId: 1,
currentChat: { meta: { assignee: { name: 'John' } } },
};
},
computed: {
currentUser() {
return {
id: 1,
accounts: [
{
id: 1,
availability_status: 'offline',
auto_offline: false,
},
],
};
},
currentAccountId() {
return 1;
},
assignableAgents() {
return agentFixtures.allAgents;
},
},
};
const wrapper = shallowMount(Component, { store, localVue });
expect(
wrapper.vm.getAgentsByUpdatedPresence(
agentFixtures.formattedAgentsByPresenceOnline
)
).toEqual(agentFixtures.formattedAgentsByPresenceOffline);
});
});