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:
@@ -2,7 +2,6 @@
|
|||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { useKeyboardEvents } from 'dashboard/composables/useKeyboardEvents';
|
import { useKeyboardEvents } from 'dashboard/composables/useKeyboardEvents';
|
||||||
import agentMixin from '../../../mixins/agentMixin.js';
|
|
||||||
import BackButton from '../BackButton.vue';
|
import BackButton from '../BackButton.vue';
|
||||||
import inboxMixin from 'shared/mixins/inboxMixin';
|
import inboxMixin from 'shared/mixins/inboxMixin';
|
||||||
import InboxName from '../InboxName.vue';
|
import InboxName from '../InboxName.vue';
|
||||||
@@ -24,7 +23,7 @@ export default {
|
|||||||
SLACardLabel,
|
SLACardLabel,
|
||||||
Linear,
|
Linear,
|
||||||
},
|
},
|
||||||
mixins: [inboxMixin, agentMixin],
|
mixins: [inboxMixin],
|
||||||
props: {
|
props: {
|
||||||
chat: {
|
chat: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import { mapGetters } from 'vuex';
|
||||||
|
import {
|
||||||
|
getSortedAgentsByAvailability,
|
||||||
|
getAgentsByUpdatedPresence,
|
||||||
|
} from 'dashboard/helper/agentHelper.js';
|
||||||
import MenuItem from './menuItem.vue';
|
import MenuItem from './menuItem.vue';
|
||||||
import MenuItemWithSubmenu from './menuItemWithSubmenu.vue';
|
import MenuItemWithSubmenu from './menuItemWithSubmenu.vue';
|
||||||
import wootConstants from 'dashboard/constants/globals';
|
import wootConstants from 'dashboard/constants/globals';
|
||||||
import agentMixin from 'dashboard/mixins/agentMixin';
|
|
||||||
import { mapGetters } from 'vuex';
|
|
||||||
import AgentLoadingPlaceholder from './agentLoadingPlaceholder.vue';
|
import AgentLoadingPlaceholder from './agentLoadingPlaceholder.vue';
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -11,7 +14,6 @@ export default {
|
|||||||
MenuItemWithSubmenu,
|
MenuItemWithSubmenu,
|
||||||
AgentLoadingPlaceholder,
|
AgentLoadingPlaceholder,
|
||||||
},
|
},
|
||||||
mixins: [agentMixin],
|
|
||||||
props: {
|
props: {
|
||||||
chatId: {
|
chatId: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@@ -112,13 +114,19 @@ export default {
|
|||||||
labels: 'labels/getLabels',
|
labels: 'labels/getLabels',
|
||||||
teams: 'teams/getTeams',
|
teams: 'teams/getTeams',
|
||||||
assignableAgentsUiFlags: 'inboxAssignableAgents/getUIFlags',
|
assignableAgentsUiFlags: 'inboxAssignableAgents/getUIFlags',
|
||||||
|
currentUser: 'getCurrentUser',
|
||||||
|
currentAccountId: 'getCurrentAccountId',
|
||||||
}),
|
}),
|
||||||
filteredAgentOnAvailability() {
|
filteredAgentOnAvailability() {
|
||||||
const agents = this.$store.getters[
|
const agents = this.$store.getters[
|
||||||
'inboxAssignableAgents/getAssignableAgents'
|
'inboxAssignableAgents/getAssignableAgents'
|
||||||
](this.inboxId);
|
](this.inboxId);
|
||||||
const agentsByUpdatedPresence = this.getAgentsByUpdatedPresence(agents);
|
const agentsByUpdatedPresence = getAgentsByUpdatedPresence(
|
||||||
const filteredAgents = this.sortedAgentsByAvailability(
|
agents,
|
||||||
|
this.currentUser,
|
||||||
|
this.currentAccountId
|
||||||
|
);
|
||||||
|
const filteredAgents = getSortedAgentsByAvailability(
|
||||||
agentsByUpdatedPresence
|
agentsByUpdatedPresence
|
||||||
);
|
);
|
||||||
return filteredAgents;
|
return filteredAgents;
|
||||||
|
|||||||
63
app/javascript/dashboard/composables/spec/fixtures/agentFixtures.js
vendored
Normal file
63
app/javascript/dashboard/composables/spec/fixtures/agentFixtures.js
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import { allAgentsData } from 'dashboard/helper/specs/fixtures/agentFixtures';
|
||||||
|
|
||||||
|
export { allAgentsData };
|
||||||
|
export const formattedAgentsData = [
|
||||||
|
{
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import { ref } from 'vue';
|
||||||
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||||
|
import { useAgentsList } from '../useAgentsList';
|
||||||
|
import { useMapGetter } from 'dashboard/composables/store';
|
||||||
|
import { allAgentsData, formattedAgentsData } from './fixtures/agentFixtures';
|
||||||
|
import * as agentHelper from 'dashboard/helper/agentHelper';
|
||||||
|
|
||||||
|
vi.mock('dashboard/composables/store');
|
||||||
|
vi.mock('dashboard/helper/agentHelper');
|
||||||
|
|
||||||
|
const mockUseMapGetter = (overrides = {}) => {
|
||||||
|
const defaultGetters = {
|
||||||
|
getCurrentUser: ref(allAgentsData[0]),
|
||||||
|
getSelectedChat: ref({ inbox_id: 1, meta: { assignee: true } }),
|
||||||
|
getCurrentAccountId: ref(1),
|
||||||
|
'inboxAssignableAgents/getAssignableAgents': ref(() => allAgentsData),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mergedGetters = { ...defaultGetters, ...overrides };
|
||||||
|
|
||||||
|
useMapGetter.mockImplementation(getter => mergedGetters[getter]);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('useAgentsList', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
agentHelper.getAgentsByUpdatedPresence.mockImplementation(agents => agents);
|
||||||
|
agentHelper.getSortedAgentsByAvailability.mockReturnValue(
|
||||||
|
formattedAgentsData.slice(1)
|
||||||
|
);
|
||||||
|
agentHelper.getCombinedAgents.mockImplementation(
|
||||||
|
(agents, includeNone, isAgentSelected) => {
|
||||||
|
if (includeNone && isAgentSelected) {
|
||||||
|
return [agentHelper.createNoneAgent, ...agents];
|
||||||
|
}
|
||||||
|
return agents;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
mockUseMapGetter();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns agentsList and assignableAgents', () => {
|
||||||
|
const { agentsList, assignableAgents } = useAgentsList();
|
||||||
|
|
||||||
|
expect(assignableAgents.value).toEqual(allAgentsData);
|
||||||
|
expect(agentsList.value).toEqual([
|
||||||
|
agentHelper.createNoneAgent,
|
||||||
|
...formattedAgentsData.slice(1),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('includes None agent when includeNoneAgent is true', () => {
|
||||||
|
const { agentsList } = useAgentsList(true);
|
||||||
|
|
||||||
|
expect(agentsList.value[0]).toEqual(agentHelper.createNoneAgent);
|
||||||
|
expect(agentsList.value.length).toBe(formattedAgentsData.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('excludes None agent when includeNoneAgent is false', () => {
|
||||||
|
const { agentsList } = useAgentsList(false);
|
||||||
|
|
||||||
|
expect(agentsList.value[0]).not.toEqual(agentHelper.createNoneAgent);
|
||||||
|
expect(agentsList.value.length).toBe(formattedAgentsData.length - 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles empty assignable agents', () => {
|
||||||
|
mockUseMapGetter({
|
||||||
|
'inboxAssignableAgents/getAssignableAgents': ref(() => []),
|
||||||
|
});
|
||||||
|
agentHelper.getSortedAgentsByAvailability.mockReturnValue([]);
|
||||||
|
|
||||||
|
const { agentsList, assignableAgents } = useAgentsList();
|
||||||
|
|
||||||
|
expect(assignableAgents.value).toEqual([]);
|
||||||
|
expect(agentsList.value).toEqual([agentHelper.createNoneAgent]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles missing inbox_id', () => {
|
||||||
|
mockUseMapGetter({
|
||||||
|
getSelectedChat: ref({ meta: { assignee: true } }),
|
||||||
|
'inboxAssignableAgents/getAssignableAgents': ref(() => []),
|
||||||
|
});
|
||||||
|
agentHelper.getSortedAgentsByAvailability.mockReturnValue([]);
|
||||||
|
|
||||||
|
const { agentsList, assignableAgents } = useAgentsList();
|
||||||
|
|
||||||
|
expect(assignableAgents.value).toEqual([]);
|
||||||
|
expect(agentsList.value).toEqual([agentHelper.createNoneAgent]);
|
||||||
|
});
|
||||||
|
});
|
||||||
57
app/javascript/dashboard/composables/useAgentsList.js
Normal file
57
app/javascript/dashboard/composables/useAgentsList.js
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { computed } from 'vue';
|
||||||
|
import { useMapGetter } from 'dashboard/composables/store';
|
||||||
|
import {
|
||||||
|
getAgentsByUpdatedPresence,
|
||||||
|
getSortedAgentsByAvailability,
|
||||||
|
getCombinedAgents,
|
||||||
|
} from 'dashboard/helper/agentHelper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A composable function that provides a list of agents for assignment.
|
||||||
|
*
|
||||||
|
* @param {boolean} [includeNoneAgent=true] - Whether to include a 'None' agent option.
|
||||||
|
* @returns {Object} An object containing the agents list and assignable agents.
|
||||||
|
*/
|
||||||
|
export function useAgentsList(includeNoneAgent = true) {
|
||||||
|
const currentUser = useMapGetter('getCurrentUser');
|
||||||
|
const currentChat = useMapGetter('getSelectedChat');
|
||||||
|
const currentAccountId = useMapGetter('getCurrentAccountId');
|
||||||
|
const assignable = useMapGetter('inboxAssignableAgents/getAssignableAgents');
|
||||||
|
|
||||||
|
const inboxId = computed(() => currentChat.value?.inbox_id);
|
||||||
|
const isAgentSelected = computed(() => currentChat.value?.meta?.assignee);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {import('vue').ComputedRef<Array>}
|
||||||
|
*/
|
||||||
|
const assignableAgents = computed(() => {
|
||||||
|
return inboxId.value ? assignable.value(inboxId.value) : [];
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {import('vue').ComputedRef<Array>}
|
||||||
|
*/
|
||||||
|
const agentsList = computed(() => {
|
||||||
|
const agents = assignableAgents.value || [];
|
||||||
|
const agentsByUpdatedPresence = getAgentsByUpdatedPresence(
|
||||||
|
agents,
|
||||||
|
currentUser.value,
|
||||||
|
currentAccountId.value
|
||||||
|
);
|
||||||
|
|
||||||
|
const filteredAgentsByAvailability = getSortedAgentsByAvailability(
|
||||||
|
agentsByUpdatedPresence
|
||||||
|
);
|
||||||
|
|
||||||
|
return getCombinedAgents(
|
||||||
|
filteredAgentsByAvailability,
|
||||||
|
includeNoneAgent,
|
||||||
|
isAgentSelected.value
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
agentsList,
|
||||||
|
assignableAgents,
|
||||||
|
};
|
||||||
|
}
|
||||||
83
app/javascript/dashboard/helper/agentHelper.js
Normal file
83
app/javascript/dashboard/helper/agentHelper.js
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/**
|
||||||
|
* Default agent object representing 'None'
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
export const createNoneAgent = {
|
||||||
|
confirmed: true,
|
||||||
|
name: 'None',
|
||||||
|
id: 0,
|
||||||
|
role: 'agent',
|
||||||
|
account_id: 0,
|
||||||
|
email: 'None',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters and sorts agents by availability status
|
||||||
|
* @param {Array} agents - List of agents
|
||||||
|
* @param {string} availability - Availability status to filter by
|
||||||
|
* @returns {Array} Filtered and sorted list of agents
|
||||||
|
*/
|
||||||
|
export const getAgentsByAvailability = (agents, availability) => {
|
||||||
|
return agents
|
||||||
|
.filter(agent => agent.availability_status === availability)
|
||||||
|
.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts agents by availability status: online, busy, then offline
|
||||||
|
* @param {Array} agents - List of agents
|
||||||
|
* @returns {Array} Sorted list of agents
|
||||||
|
*/
|
||||||
|
export const getSortedAgentsByAvailability = agents => {
|
||||||
|
const onlineAgents = getAgentsByAvailability(agents, 'online');
|
||||||
|
const busyAgents = getAgentsByAvailability(agents, 'busy');
|
||||||
|
const offlineAgents = getAgentsByAvailability(agents, 'offline');
|
||||||
|
const filteredAgents = [...onlineAgents, ...busyAgents, ...offlineAgents];
|
||||||
|
return filteredAgents;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the availability status of the current user based on the current account
|
||||||
|
* @param {Array} agents - List of agents
|
||||||
|
* @param {Object} currentUser - Current user object
|
||||||
|
* @param {number} currentAccountId - ID of the current account
|
||||||
|
* @returns {Array} Updated list of agents with dynamic presence
|
||||||
|
*/
|
||||||
|
// Here we are updating the availability status of the current user dynamically
|
||||||
|
// based on the current account availability status
|
||||||
|
export const getAgentsByUpdatedPresence = (
|
||||||
|
agents,
|
||||||
|
currentUser,
|
||||||
|
currentAccountId
|
||||||
|
) => {
|
||||||
|
const agentsWithDynamicPresenceUpdate = agents.map(item =>
|
||||||
|
item.id === currentUser.id
|
||||||
|
? {
|
||||||
|
...item,
|
||||||
|
availability_status: currentUser.accounts.find(
|
||||||
|
account => account.id === currentAccountId
|
||||||
|
).availability_status,
|
||||||
|
}
|
||||||
|
: item
|
||||||
|
);
|
||||||
|
return agentsWithDynamicPresenceUpdate;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines the filtered agents with the 'None' agent option if applicable.
|
||||||
|
*
|
||||||
|
* @param {Array} filteredAgentsByAvailability - The list of agents sorted by availability.
|
||||||
|
* @param {boolean} includeNoneAgent - Whether to include the 'None' agent option.
|
||||||
|
* @param {boolean} isAgentSelected - Whether an agent is currently selected.
|
||||||
|
* @returns {Array} The combined list of agents, potentially including the 'None' agent.
|
||||||
|
*/
|
||||||
|
export const getCombinedAgents = (
|
||||||
|
filteredAgentsByAvailability,
|
||||||
|
includeNoneAgent,
|
||||||
|
isAgentSelected
|
||||||
|
) => {
|
||||||
|
return [
|
||||||
|
...(includeNoneAgent && isAgentSelected ? [createNoneAgent] : []),
|
||||||
|
...filteredAgentsByAvailability,
|
||||||
|
];
|
||||||
|
};
|
||||||
131
app/javascript/dashboard/helper/specs/agentHelper.spec.js
Normal file
131
app/javascript/dashboard/helper/specs/agentHelper.spec.js
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
import {
|
||||||
|
getAgentsByAvailability,
|
||||||
|
getSortedAgentsByAvailability,
|
||||||
|
getAgentsByUpdatedPresence,
|
||||||
|
getCombinedAgents,
|
||||||
|
createNoneAgent,
|
||||||
|
} from '../agentHelper';
|
||||||
|
import {
|
||||||
|
allAgentsData,
|
||||||
|
onlineAgentsData,
|
||||||
|
busyAgentsData,
|
||||||
|
offlineAgentsData,
|
||||||
|
sortedByAvailability,
|
||||||
|
formattedAgentsByPresenceOnline,
|
||||||
|
formattedAgentsByPresenceOffline,
|
||||||
|
} from 'dashboard/helper/specs/fixtures/agentFixtures';
|
||||||
|
|
||||||
|
describe('agentHelper', () => {
|
||||||
|
describe('getAgentsByAvailability', () => {
|
||||||
|
it('returns agents by availability', () => {
|
||||||
|
expect(getAgentsByAvailability(allAgentsData, 'online')).toEqual(
|
||||||
|
onlineAgentsData
|
||||||
|
);
|
||||||
|
expect(getAgentsByAvailability(allAgentsData, 'busy')).toEqual(
|
||||||
|
busyAgentsData
|
||||||
|
);
|
||||||
|
expect(getAgentsByAvailability(allAgentsData, 'offline')).toEqual(
|
||||||
|
offlineAgentsData
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getSortedAgentsByAvailability', () => {
|
||||||
|
it('returns sorted agents by availability', () => {
|
||||||
|
expect(getSortedAgentsByAvailability(allAgentsData)).toEqual(
|
||||||
|
sortedByAvailability
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns an empty array when given an empty input', () => {
|
||||||
|
expect(getSortedAgentsByAvailability([])).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('maintains the order of agents with the same availability status', () => {
|
||||||
|
const result = getSortedAgentsByAvailability(allAgentsData);
|
||||||
|
expect(result[2].name).toBe('Honey Bee');
|
||||||
|
expect(result[3].name).toBe('Samuel Keta');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getAgentsByUpdatedPresence', () => {
|
||||||
|
it('returns agents with updated presence', () => {
|
||||||
|
const currentUser = {
|
||||||
|
id: 1,
|
||||||
|
accounts: [{ id: 1, availability_status: 'offline' }],
|
||||||
|
};
|
||||||
|
const currentAccountId = 1;
|
||||||
|
|
||||||
|
expect(
|
||||||
|
getAgentsByUpdatedPresence(
|
||||||
|
formattedAgentsByPresenceOnline,
|
||||||
|
currentUser,
|
||||||
|
currentAccountId
|
||||||
|
)
|
||||||
|
).toEqual(formattedAgentsByPresenceOffline);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not modify other agents presence', () => {
|
||||||
|
const currentUser = {
|
||||||
|
id: 2,
|
||||||
|
accounts: [{ id: 1, availability_status: 'offline' }],
|
||||||
|
};
|
||||||
|
const currentAccountId = 1;
|
||||||
|
|
||||||
|
expect(
|
||||||
|
getAgentsByUpdatedPresence(
|
||||||
|
formattedAgentsByPresenceOnline,
|
||||||
|
currentUser,
|
||||||
|
currentAccountId
|
||||||
|
)
|
||||||
|
).toEqual(formattedAgentsByPresenceOnline);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles empty agent list', () => {
|
||||||
|
const currentUser = {
|
||||||
|
id: 1,
|
||||||
|
accounts: [{ id: 1, availability_status: 'offline' }],
|
||||||
|
};
|
||||||
|
const currentAccountId = 1;
|
||||||
|
|
||||||
|
expect(
|
||||||
|
getAgentsByUpdatedPresence([], currentUser, currentAccountId)
|
||||||
|
).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getCombinedAgents', () => {
|
||||||
|
it('includes None agent when includeNoneAgent is true and isAgentSelected is true', () => {
|
||||||
|
const result = getCombinedAgents(sortedByAvailability, true, true);
|
||||||
|
expect(result).toEqual([createNoneAgent, ...sortedByAvailability]);
|
||||||
|
expect(result.length).toBe(sortedByAvailability.length + 1);
|
||||||
|
expect(result[0]).toEqual(createNoneAgent);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('excludes None agent when includeNoneAgent is false', () => {
|
||||||
|
const result = getCombinedAgents(sortedByAvailability, false, true);
|
||||||
|
expect(result).toEqual(sortedByAvailability);
|
||||||
|
expect(result.length).toBe(sortedByAvailability.length);
|
||||||
|
expect(result[0]).not.toEqual(createNoneAgent);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('excludes None agent when isAgentSelected is false', () => {
|
||||||
|
const result = getCombinedAgents(sortedByAvailability, true, false);
|
||||||
|
expect(result).toEqual(sortedByAvailability);
|
||||||
|
expect(result.length).toBe(sortedByAvailability.length);
|
||||||
|
expect(result[0]).not.toEqual(createNoneAgent);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns only filtered agents when both includeNoneAgent and isAgentSelected are false', () => {
|
||||||
|
const result = getCombinedAgents(sortedByAvailability, false, false);
|
||||||
|
expect(result).toEqual(sortedByAvailability);
|
||||||
|
expect(result.length).toBe(sortedByAvailability.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles empty filteredAgentsByAvailability array', () => {
|
||||||
|
const result = getCombinedAgents([], true, true);
|
||||||
|
expect(result).toEqual([createNoneAgent]);
|
||||||
|
expect(result.length).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
184
app/javascript/dashboard/helper/specs/fixtures/agentFixtures.js
vendored
Normal file
184
app/javascript/dashboard/helper/specs/fixtures/agentFixtures.js
vendored
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
export const allAgentsData = [
|
||||||
|
{
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export const onlineAgentsData = [
|
||||||
|
{
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export const busyAgentsData = [
|
||||||
|
{
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export const offlineAgentsData = [
|
||||||
|
{
|
||||||
|
account_id: 1,
|
||||||
|
availability_status: 'offline',
|
||||||
|
available_name: 'James K',
|
||||||
|
confirmed: true,
|
||||||
|
email: 'james@chatwoot.com',
|
||||||
|
id: 3,
|
||||||
|
name: 'James Koti',
|
||||||
|
role: 'agent',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export const 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',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export const formattedAgentsByPresenceOnline = [
|
||||||
|
{
|
||||||
|
account_id: 1,
|
||||||
|
availability_status: 'online',
|
||||||
|
available_name: 'Abraham',
|
||||||
|
confirmed: true,
|
||||||
|
email: 'abr@chatwoot.com',
|
||||||
|
id: 1,
|
||||||
|
name: 'Abraham Keta',
|
||||||
|
role: 'agent',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export const formattedAgentsByPresenceOffline = [
|
||||||
|
{
|
||||||
|
account_id: 1,
|
||||||
|
availability_status: 'offline',
|
||||||
|
available_name: 'Abraham',
|
||||||
|
confirmed: true,
|
||||||
|
email: 'abr@chatwoot.com',
|
||||||
|
id: 1,
|
||||||
|
name: 'Abraham Keta',
|
||||||
|
role: 'agent',
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -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;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -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',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
@@ -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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,18 +1,17 @@
|
|||||||
<script>
|
<script>
|
||||||
import '@chatwoot/ninja-keys';
|
import '@chatwoot/ninja-keys';
|
||||||
import { useConversationLabels } from 'dashboard/composables/useConversationLabels';
|
import { useConversationLabels } from 'dashboard/composables/useConversationLabels';
|
||||||
|
import { useAgentsList } from 'dashboard/composables/useAgentsList';
|
||||||
import wootConstants from 'dashboard/constants/globals';
|
import wootConstants from 'dashboard/constants/globals';
|
||||||
import conversationHotKeysMixin from './conversationHotKeys';
|
import conversationHotKeysMixin from './conversationHotKeys';
|
||||||
import bulkActionsHotKeysMixin from './bulkActionsHotKeys';
|
import bulkActionsHotKeysMixin from './bulkActionsHotKeys';
|
||||||
import inboxHotKeysMixin from './inboxHotKeys';
|
import inboxHotKeysMixin from './inboxHotKeys';
|
||||||
import goToCommandHotKeys from './goToCommandHotKeys';
|
import goToCommandHotKeys from './goToCommandHotKeys';
|
||||||
import appearanceHotKeys from './appearanceHotKeys';
|
import appearanceHotKeys from './appearanceHotKeys';
|
||||||
import agentMixin from 'dashboard/mixins/agentMixin';
|
|
||||||
import { GENERAL_EVENTS } from '../../../helper/AnalyticsHelper/events';
|
import { GENERAL_EVENTS } from '../../../helper/AnalyticsHelper/events';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [
|
mixins: [
|
||||||
agentMixin,
|
|
||||||
conversationHotKeysMixin,
|
conversationHotKeysMixin,
|
||||||
bulkActionsHotKeysMixin,
|
bulkActionsHotKeysMixin,
|
||||||
inboxHotKeysMixin,
|
inboxHotKeysMixin,
|
||||||
@@ -28,7 +27,11 @@ export default {
|
|||||||
removeLabelFromConversation,
|
removeLabelFromConversation,
|
||||||
} = useConversationLabels();
|
} = useConversationLabels();
|
||||||
|
|
||||||
|
const { agentsList, assignableAgents } = useAgentsList();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
agentsList,
|
||||||
|
assignableAgents,
|
||||||
activeLabels,
|
activeLabels,
|
||||||
inactiveLabels,
|
inactiveLabels,
|
||||||
addLabelToConversation,
|
addLabelToConversation,
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
|
import { useAgentsList } from 'dashboard/composables/useAgentsList';
|
||||||
import ContactDetailsItem from './ContactDetailsItem.vue';
|
import ContactDetailsItem from './ContactDetailsItem.vue';
|
||||||
import MultiselectDropdown from 'shared/components/ui/MultiselectDropdown.vue';
|
import MultiselectDropdown from 'shared/components/ui/MultiselectDropdown.vue';
|
||||||
import ConversationLabels from './labels/LabelBox.vue';
|
import ConversationLabels from './labels/LabelBox.vue';
|
||||||
import agentMixin from 'dashboard/mixins/agentMixin';
|
|
||||||
import { CONVERSATION_PRIORITY } from '../../../../shared/constants/messages';
|
import { CONVERSATION_PRIORITY } from '../../../../shared/constants/messages';
|
||||||
import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events';
|
import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events';
|
||||||
|
|
||||||
@@ -15,19 +15,17 @@ export default {
|
|||||||
MultiselectDropdown,
|
MultiselectDropdown,
|
||||||
ConversationLabels,
|
ConversationLabels,
|
||||||
},
|
},
|
||||||
mixins: [agentMixin],
|
|
||||||
props: {
|
props: {
|
||||||
conversationId: {
|
conversationId: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
// inboxId prop is used in /mixins/agentMixin,
|
},
|
||||||
// remove this props when refactoring to composable if not needed
|
setup() {
|
||||||
// eslint-disable-next-line vue/no-unused-properties
|
const { agentsList } = useAgentsList();
|
||||||
inboxId: {
|
return {
|
||||||
type: Number,
|
agentsList,
|
||||||
default: undefined,
|
};
|
||||||
},
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
import Spinner from 'shared/components/Spinner.vue';
|
import Spinner from 'shared/components/Spinner.vue';
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import agentMixin from 'dashboard/mixins/agentMixin';
|
import { useAgentsList } from 'dashboard/composables/useAgentsList';
|
||||||
|
|
||||||
import ThumbnailGroup from 'dashboard/components/widgets/ThumbnailGroup.vue';
|
import ThumbnailGroup from 'dashboard/components/widgets/ThumbnailGroup.vue';
|
||||||
import MultiselectDropdownItems from 'shared/components/ui/MultiselectDropdownItems.vue';
|
import MultiselectDropdownItems from 'shared/components/ui/MultiselectDropdownItems.vue';
|
||||||
|
|
||||||
@@ -12,19 +13,17 @@ export default {
|
|||||||
ThumbnailGroup,
|
ThumbnailGroup,
|
||||||
MultiselectDropdownItems,
|
MultiselectDropdownItems,
|
||||||
},
|
},
|
||||||
mixins: [agentMixin],
|
|
||||||
props: {
|
props: {
|
||||||
conversationId: {
|
conversationId: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
// inboxId prop is used in /mixins/agentMixin,
|
},
|
||||||
// remove this props when refactoring to composable if not needed
|
setup() {
|
||||||
// eslint-disable-next-line vue/no-unused-properties
|
const { agentsList } = useAgentsList(false);
|
||||||
inboxId: {
|
return {
|
||||||
type: Number,
|
agentsList,
|
||||||
default: undefined,
|
};
|
||||||
},
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user