Merge branch 'develop' into deploy-apr-15
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
import * as MutationHelpers from 'shared/helpers/vuex/mutationHelpers';
|
||||
import types from '../mutation-types';
|
||||
import SLAReportsAPI from '../../api/slaReports';
|
||||
import { downloadCsvFile } from 'dashboard/helper/downloadHelper';
|
||||
export const state = {
|
||||
records: [],
|
||||
metrics: {
|
||||
numberOfConversations: 0,
|
||||
numberOfSLAMisses: 0,
|
||||
hitRate: '0%',
|
||||
},
|
||||
uiFlags: {
|
||||
isFetching: false,
|
||||
isFetchingMetrics: false,
|
||||
},
|
||||
meta: {
|
||||
count: 0,
|
||||
currentPage: 1,
|
||||
},
|
||||
};
|
||||
|
||||
export const getters = {
|
||||
getAll(_state) {
|
||||
return _state.records;
|
||||
},
|
||||
getMeta(_state) {
|
||||
return _state.meta;
|
||||
},
|
||||
getMetrics(_state) {
|
||||
return _state.metrics;
|
||||
},
|
||||
getUIFlags(_state) {
|
||||
return _state.uiFlags;
|
||||
},
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
get: async function getResponses({ commit }, params) {
|
||||
commit(types.SET_SLA_REPORTS_UI_FLAG, { isFetching: true });
|
||||
try {
|
||||
const response = await SLAReportsAPI.get(params);
|
||||
const { payload, meta } = response.data;
|
||||
|
||||
commit(types.SET_SLA_REPORTS, payload);
|
||||
commit(types.SET_SLA_REPORTS_META, meta);
|
||||
} catch (error) {
|
||||
throw new Error(error);
|
||||
} finally {
|
||||
commit(types.SET_SLA_REPORTS_UI_FLAG, { isFetching: false });
|
||||
}
|
||||
},
|
||||
getMetrics: async function getMetrics({ commit }, params) {
|
||||
commit(types.SET_SLA_REPORTS_UI_FLAG, { isFetchingMetrics: true });
|
||||
try {
|
||||
const response = await SLAReportsAPI.getMetrics(params);
|
||||
commit(types.SET_SLA_REPORTS_METRICS, response.data);
|
||||
} catch (error) {
|
||||
// Ignore error
|
||||
} finally {
|
||||
commit(types.SET_SLA_REPORTS_UI_FLAG, { isFetchingMetrics: false });
|
||||
}
|
||||
},
|
||||
download(_, params) {
|
||||
return SLAReportsAPI.download(params).then(response => {
|
||||
downloadCsvFile(params.fileName, response.data);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const mutations = {
|
||||
[types.SET_SLA_REPORTS_UI_FLAG](_state, data) {
|
||||
_state.uiFlags = {
|
||||
..._state.uiFlags,
|
||||
...data,
|
||||
};
|
||||
},
|
||||
|
||||
[types.SET_SLA_REPORTS]: MutationHelpers.set,
|
||||
[types.SET_SLA_REPORTS_METRICS](
|
||||
_state,
|
||||
{
|
||||
number_of_sla_misses: numberOfSLAMisses,
|
||||
hit_rate: hitRate,
|
||||
total_applied_slas: numberOfConversations,
|
||||
}
|
||||
) {
|
||||
_state.metrics = {
|
||||
numberOfSLAMisses,
|
||||
hitRate,
|
||||
numberOfConversations,
|
||||
};
|
||||
},
|
||||
[types.SET_SLA_REPORTS_META](_state, { count, current_page: currentPage }) {
|
||||
_state.meta = {
|
||||
count,
|
||||
currentPage,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
getters,
|
||||
actions,
|
||||
mutations,
|
||||
};
|
||||
@@ -1,12 +1,15 @@
|
||||
import * as MutationHelpers from 'shared/helpers/vuex/mutationHelpers';
|
||||
import * as types from '../mutation-types';
|
||||
import AccountAPI from '../../api/account';
|
||||
import { differenceInDays } from 'date-fns';
|
||||
import EnterpriseAccountAPI from '../../api/enterprise/account';
|
||||
import { throwErrorMessage } from '../utils/api';
|
||||
|
||||
const findRecordById = ($state, id) =>
|
||||
$state.records.find(record => record.id === Number(id)) || {};
|
||||
|
||||
const TRIAL_PERIOD_DAYS = 15;
|
||||
|
||||
const state = {
|
||||
records: [],
|
||||
uiFlags: {
|
||||
@@ -19,26 +22,19 @@ const state = {
|
||||
|
||||
export const getters = {
|
||||
getAccount: $state => id => {
|
||||
return $state.records.find(record => record.id === Number(id)) || {};
|
||||
return findRecordById($state, id);
|
||||
},
|
||||
getUIFlags($state) {
|
||||
return $state.uiFlags;
|
||||
},
|
||||
isFeatureEnabledonAccount:
|
||||
($state, _, __, rootGetters) => (id, featureName) => {
|
||||
// If a user is SuperAdmin and has access to the account, then they would see all the available features
|
||||
const isUserASuperAdmin =
|
||||
rootGetters.getCurrentUser?.type === 'SuperAdmin';
|
||||
if (isUserASuperAdmin) {
|
||||
return true;
|
||||
}
|
||||
isTrialAccount: $state => id => {
|
||||
const account = findRecordById($state, id);
|
||||
const createdAt = new Date(account.created_at);
|
||||
const diffDays = differenceInDays(new Date(), createdAt);
|
||||
|
||||
const { features = {} } = findRecordById($state, id);
|
||||
|
||||
return features[featureName] || false;
|
||||
},
|
||||
// There are some features which can be enabled/disabled globally
|
||||
isFeatureEnabledGlobally: $state => (id, featureName) => {
|
||||
return diffDays <= TRIAL_PERIOD_DAYS;
|
||||
},
|
||||
isFeatureEnabledonAccount: $state => (id, featureName) => {
|
||||
const { features = {} } = findRecordById($state, id);
|
||||
return features[featureName] || false;
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@ import types from '../mutation-types';
|
||||
import BulkActionsAPI from '../../api/bulkActions';
|
||||
|
||||
export const state = {
|
||||
selectedConversationIds: [],
|
||||
uiFlags: {
|
||||
isUpdating: false,
|
||||
},
|
||||
@@ -11,6 +12,9 @@ export const getters = {
|
||||
getUIFlags(_state) {
|
||||
return _state.uiFlags;
|
||||
},
|
||||
getSelectedConversationIds(_state) {
|
||||
return _state.selectedConversationIds;
|
||||
},
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
@@ -24,6 +28,15 @@ export const actions = {
|
||||
commit(types.SET_BULK_ACTIONS_FLAG, { isUpdating: false });
|
||||
}
|
||||
},
|
||||
setSelectedConversationIds({ commit }, id) {
|
||||
commit(types.SET_SELECTED_CONVERSATION_IDS, id);
|
||||
},
|
||||
removeSelectedConversationIds({ commit }, id) {
|
||||
commit(types.REMOVE_SELECTED_CONVERSATION_IDS, id);
|
||||
},
|
||||
clearSelectedConversationIds({ commit }) {
|
||||
commit(types.CLEAR_SELECTED_CONVERSATION_IDS);
|
||||
},
|
||||
};
|
||||
|
||||
export const mutations = {
|
||||
@@ -33,6 +46,23 @@ export const mutations = {
|
||||
...data,
|
||||
};
|
||||
},
|
||||
[types.SET_SELECTED_CONVERSATION_IDS](_state, ids) {
|
||||
// Check if ids is an array, if not, convert it to an array
|
||||
const idsArray = Array.isArray(ids) ? ids : [ids];
|
||||
|
||||
// Concatenate the new IDs ensuring no duplicates
|
||||
_state.selectedConversationIds = [
|
||||
...new Set([..._state.selectedConversationIds, ...idsArray]),
|
||||
];
|
||||
},
|
||||
[types.REMOVE_SELECTED_CONVERSATION_IDS](_state, id) {
|
||||
_state.selectedConversationIds = _state.selectedConversationIds.filter(
|
||||
item => item !== id
|
||||
);
|
||||
},
|
||||
[types.CLEAR_SELECTED_CONVERSATION_IDS](_state) {
|
||||
_state.selectedConversationIds = [];
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
@@ -138,9 +138,10 @@ export const actions = {
|
||||
}
|
||||
},
|
||||
|
||||
export: async ({ commit }) => {
|
||||
export: async ({ commit }, { payload, label }) => {
|
||||
try {
|
||||
await ContactAPI.exportContacts();
|
||||
await ContactAPI.exportContacts({ payload, label });
|
||||
|
||||
commit(types.SET_CONTACT_UI_FLAG, { isCreating: false });
|
||||
} catch (error) {
|
||||
commit(types.SET_CONTACT_UI_FLAG, { isCreating: false });
|
||||
|
||||
@@ -466,6 +466,10 @@ const actions = {
|
||||
commit(types.ASSIGN_PRIORITY, { priority, conversationId });
|
||||
},
|
||||
|
||||
setContextMenuChatId({ commit }, chatId) {
|
||||
commit(types.SET_CONTEXT_MENU_CHAT_ID, chatId);
|
||||
},
|
||||
|
||||
...messageReadActions,
|
||||
...messageTranslateActions,
|
||||
};
|
||||
|
||||
@@ -100,6 +100,10 @@ const getters = {
|
||||
getConversationLastSeen: _state => {
|
||||
return _state.conversationLastSeen;
|
||||
},
|
||||
|
||||
getContextMenuChatId: _state => {
|
||||
return _state.contextMenuChatId;
|
||||
},
|
||||
};
|
||||
|
||||
export default getters;
|
||||
|
||||
@@ -15,6 +15,7 @@ const state = {
|
||||
currentInbox: null,
|
||||
selectedChatId: null,
|
||||
appliedFilters: [],
|
||||
contextMenuChatId: null,
|
||||
conversationParticipants: [],
|
||||
conversationLastSeen: null,
|
||||
syncConversationsMessages: {},
|
||||
@@ -281,6 +282,10 @@ export const mutations = {
|
||||
) {
|
||||
_state.syncConversationsMessages[conversationId] = messageId;
|
||||
},
|
||||
|
||||
[types.SET_CONTEXT_MENU_CHAT_ID](_state, chatId) {
|
||||
_state.contextMenuChatId = chatId;
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
@@ -21,9 +21,13 @@ const state = {
|
||||
};
|
||||
|
||||
const isAValidAppIntegration = integration => {
|
||||
return ['dialogflow', 'dyte', 'google_translate', 'openai'].includes(
|
||||
integration.id
|
||||
);
|
||||
return [
|
||||
'dialogflow',
|
||||
'dyte',
|
||||
'google_translate',
|
||||
'openai',
|
||||
'linear',
|
||||
].includes(integration.id);
|
||||
};
|
||||
export const getters = {
|
||||
getIntegrations($state) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { applyInboxPageFilters, sortComparator } from './helpers';
|
||||
import { sortComparator } from './helpers';
|
||||
|
||||
export const getters = {
|
||||
getNotifications($state) {
|
||||
@@ -6,14 +6,14 @@ export const getters = {
|
||||
},
|
||||
getFilteredNotifications: $state => filters => {
|
||||
const sortOrder = filters.sortOrder === 'desc' ? 'newest' : 'oldest';
|
||||
const filteredNotifications = Object.values($state.records).filter(
|
||||
notification => applyInboxPageFilters(notification, filters)
|
||||
);
|
||||
const sortedNotifications = filteredNotifications.sort((a, b) =>
|
||||
sortComparator(a, b, sortOrder)
|
||||
const sortedNotifications = Object.values($state.records).sort((n1, n2) =>
|
||||
sortComparator(n1, n2, sortOrder)
|
||||
);
|
||||
return sortedNotifications;
|
||||
},
|
||||
getNotificationById: $state => id => {
|
||||
return $state.records[id] || {};
|
||||
},
|
||||
getUIFlags($state) {
|
||||
return $state.uiFlags;
|
||||
},
|
||||
|
||||
@@ -1,31 +1,3 @@
|
||||
export const filterByStatus = (snoozedUntil, filterStatus) =>
|
||||
filterStatus === 'snoozed' ? !!snoozedUntil : !snoozedUntil;
|
||||
|
||||
export const filterByType = (readAt, filterType) =>
|
||||
filterType === 'read' ? !!readAt : !readAt;
|
||||
|
||||
export const filterByTypeAndStatus = (
|
||||
readAt,
|
||||
snoozedUntil,
|
||||
filterType,
|
||||
filterStatus
|
||||
) => {
|
||||
const shouldFilterByStatus = filterByStatus(snoozedUntil, filterStatus);
|
||||
const shouldFilterByType = filterByType(readAt, filterType);
|
||||
return shouldFilterByStatus && shouldFilterByType;
|
||||
};
|
||||
|
||||
export const applyInboxPageFilters = (notification, filters) => {
|
||||
const { status, type } = filters;
|
||||
const { read_at: readAt, snoozed_until: snoozedUntil } = notification;
|
||||
|
||||
if (status && type)
|
||||
return filterByTypeAndStatus(readAt, snoozedUntil, type, status);
|
||||
if (status && !type) return filterByStatus(snoozedUntil, status);
|
||||
if (!status && type) return filterByType(readAt, type);
|
||||
return true;
|
||||
};
|
||||
|
||||
const INBOX_SORT_OPTIONS = {
|
||||
newest: 'desc',
|
||||
oldest: 'asc',
|
||||
|
||||
@@ -28,6 +28,8 @@ const state = {
|
||||
avg_first_response_time: false,
|
||||
avg_resolution_time: false,
|
||||
resolutions_count: false,
|
||||
bot_resolutions_count: false,
|
||||
bot_handoffs_count: false,
|
||||
reply_time: false,
|
||||
},
|
||||
data: {
|
||||
@@ -37,10 +39,17 @@ const state = {
|
||||
avg_first_response_time: [],
|
||||
avg_resolution_time: [],
|
||||
resolutions_count: [],
|
||||
bot_resolutions_count: [],
|
||||
bot_handoffs_count: [],
|
||||
reply_time: [],
|
||||
},
|
||||
},
|
||||
accountSummary: accountSummaryInitialData,
|
||||
botSummary: {
|
||||
bot_resolutions_count: 0,
|
||||
bot_handoffs_count: 0,
|
||||
previous: {},
|
||||
},
|
||||
overview: {
|
||||
uiFlags: {
|
||||
isFetchingAccountConversationMetric: false,
|
||||
@@ -62,6 +71,9 @@ const getters = {
|
||||
getAccountSummary(_state) {
|
||||
return _state.accountSummary;
|
||||
},
|
||||
getBotSummary(_state) {
|
||||
return _state.botSummary;
|
||||
},
|
||||
getAccountConversationMetric(_state) {
|
||||
return _state.overview.accountConversationMetric;
|
||||
},
|
||||
@@ -126,6 +138,20 @@ export const actions = {
|
||||
commit(types.default.TOGGLE_ACCOUNT_REPORT_LOADING, false);
|
||||
});
|
||||
},
|
||||
fetchBotSummary({ commit }, reportObj) {
|
||||
Report.getBotSummary({
|
||||
from: reportObj.from,
|
||||
to: reportObj.to,
|
||||
groupBy: reportObj.groupBy,
|
||||
businessHours: reportObj.businessHours,
|
||||
})
|
||||
.then(botSummary => {
|
||||
commit(types.default.SET_BOT_SUMMARY, botSummary.data);
|
||||
})
|
||||
.catch(() => {
|
||||
commit(types.default.TOGGLE_ACCOUNT_REPORT_LOADING, false);
|
||||
});
|
||||
},
|
||||
fetchLiveConversationMetric({ commit }, params = {}) {
|
||||
commit(types.default.TOGGLE_ACCOUNT_CONVERSATION_METRIC_LOADING, true);
|
||||
liveReports
|
||||
@@ -261,6 +287,9 @@ const mutations = {
|
||||
[types.default.SET_ACCOUNT_SUMMARY](_state, summaryData) {
|
||||
_state.accountSummary = summaryData;
|
||||
},
|
||||
[types.default.SET_BOT_SUMMARY](_state, summaryData) {
|
||||
_state.botSummary = summaryData;
|
||||
},
|
||||
[types.default.SET_ACCOUNT_CONVERSATION_METRIC](_state, metricData) {
|
||||
_state.overview.accountConversationMetric = metricData;
|
||||
},
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import * as MutationHelpers from 'shared/helpers/vuex/mutationHelpers';
|
||||
import types from '../mutation-types';
|
||||
import SlaAPI from '../../api/sla';
|
||||
import AnalyticsHelper from '../../helper/AnalyticsHelper';
|
||||
import { SLA_EVENTS } from '../../helper/AnalyticsHelper/events';
|
||||
import { throwErrorMessage } from '../utils/api';
|
||||
|
||||
export const state = {
|
||||
records: [],
|
||||
uiFlags: {
|
||||
isFetching: false,
|
||||
isFetchingItem: false,
|
||||
isCreating: false,
|
||||
isDeleting: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const getters = {
|
||||
getSLA(_state) {
|
||||
return _state.records;
|
||||
},
|
||||
getUIFlags(_state) {
|
||||
return _state.uiFlags;
|
||||
},
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
get: async function get({ commit }) {
|
||||
commit(types.SET_SLA_UI_FLAG, { isFetching: true });
|
||||
try {
|
||||
const response = await SlaAPI.get();
|
||||
commit(types.SET_SLA, response.data.payload);
|
||||
} catch (error) {
|
||||
// Ignore error
|
||||
} finally {
|
||||
commit(types.SET_SLA_UI_FLAG, { isFetching: false });
|
||||
}
|
||||
},
|
||||
|
||||
create: async function create({ commit }, slaObj) {
|
||||
commit(types.SET_SLA_UI_FLAG, { isCreating: true });
|
||||
try {
|
||||
const response = await SlaAPI.create(slaObj);
|
||||
AnalyticsHelper.track(SLA_EVENTS.CREATE);
|
||||
commit(types.ADD_SLA, response.data.payload);
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_SLA_UI_FLAG, { isCreating: false });
|
||||
}
|
||||
},
|
||||
|
||||
delete: async function deleteSla({ commit }, id) {
|
||||
commit(types.SET_SLA_UI_FLAG, { isDeleting: true });
|
||||
try {
|
||||
await SlaAPI.delete(id);
|
||||
AnalyticsHelper.track(SLA_EVENTS.DELETED);
|
||||
commit(types.DELETE_SLA, id);
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_SLA_UI_FLAG, { isDeleting: false });
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export const mutations = {
|
||||
[types.SET_SLA_UI_FLAG](_state, data) {
|
||||
_state.uiFlags = {
|
||||
..._state.uiFlags,
|
||||
...data,
|
||||
};
|
||||
},
|
||||
|
||||
[types.SET_SLA]: MutationHelpers.set,
|
||||
[types.ADD_SLA]: MutationHelpers.create,
|
||||
[types.DELETE_SLA]: MutationHelpers.destroy,
|
||||
};
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
getters,
|
||||
actions,
|
||||
mutations,
|
||||
};
|
||||
@@ -52,13 +52,4 @@ describe('#getters', () => {
|
||||
)(1, 'auto_resolve_conversations')
|
||||
).toEqual(true);
|
||||
});
|
||||
|
||||
it('isFeatureEnabledGlobally', () => {
|
||||
const state = {
|
||||
records: [accountData],
|
||||
};
|
||||
expect(
|
||||
getters.isFeatureEnabledGlobally(state)(1, 'auto_resolve_conversations')
|
||||
).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -25,4 +25,28 @@ describe('#actions', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
describe('#setSelectedConversationIds', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
await actions.setSelectedConversationIds({ commit }, payload.ids);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.default.SET_SELECTED_CONVERSATION_IDS, payload.ids],
|
||||
]);
|
||||
});
|
||||
});
|
||||
describe('#removeSelectedConversationIds', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
await actions.removeSelectedConversationIds({ commit }, payload.ids);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.default.REMOVE_SELECTED_CONVERSATION_IDS, payload.ids],
|
||||
]);
|
||||
});
|
||||
});
|
||||
describe('#clearSelectedConversationIds', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
await actions.clearSelectedConversationIds({ commit });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.default.CLEAR_SELECTED_CONVERSATION_IDS],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,4 +11,10 @@ describe('#getters', () => {
|
||||
isUpdating: false,
|
||||
});
|
||||
});
|
||||
it('getSelectedConversationIds', () => {
|
||||
const state = {
|
||||
selectedConversationIds: [1, 2, 3],
|
||||
};
|
||||
expect(getters.getSelectedConversationIds(state)).toEqual([1, 2, 3]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,4 +9,25 @@ describe('#mutations', () => {
|
||||
expect(state.uiFlags.isUpdating).toEqual(true);
|
||||
});
|
||||
});
|
||||
describe('#setSelectedConversationIds', () => {
|
||||
it('set selected conversation ids', () => {
|
||||
const state = { selectedConversationIds: [] };
|
||||
mutations[types.SET_SELECTED_CONVERSATION_IDS](state, [1, 2, 3]);
|
||||
expect(state.selectedConversationIds).toEqual([1, 2, 3]);
|
||||
});
|
||||
});
|
||||
describe('#removeSelectedConversationIds', () => {
|
||||
it('remove selected conversation ids', () => {
|
||||
const state = { selectedConversationIds: [1, 2, 3] };
|
||||
mutations[types.REMOVE_SELECTED_CONVERSATION_IDS](state, 1);
|
||||
expect(state.selectedConversationIds).toEqual([2, 3]);
|
||||
});
|
||||
});
|
||||
describe('#clearSelectedConversationIds', () => {
|
||||
it('clear selected conversation ids', () => {
|
||||
const state = { selectedConversationIds: [1, 2, 3] };
|
||||
mutations[types.CLEAR_SELECTED_CONVERSATION_IDS](state);
|
||||
expect(state.selectedConversationIds).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -652,4 +652,11 @@ describe('#addMentions', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setContextMenuChatId', () => {
|
||||
it('sets the context menu chat id', () => {
|
||||
actions.setContextMenuChatId({ commit }, 1);
|
||||
expect(commit.mock.calls).toEqual([[types.SET_CONTEXT_MENU_CHAT_ID, 1]]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -272,4 +272,11 @@ describe('#getters', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getContextMenuChatId', () => {
|
||||
it('returns the context menu chat id', () => {
|
||||
const state = { contextMenuChatId: 1 };
|
||||
expect(getters.getContextMenuChatId(state)).toEqual(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -403,4 +403,12 @@ describe('#mutations', () => {
|
||||
expect(state.allConversations[0].attachments).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#SET_CONTEXT_MENU_CHAT_ID', () => {
|
||||
it('sets the context menu chat id', () => {
|
||||
const state = { contextMenuChatId: 1 };
|
||||
mutations[types.SET_CONTEXT_MENU_CHAT_ID](state, 2);
|
||||
expect(state.contextMenuChatId).toEqual(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -34,6 +34,8 @@ describe('#getters', () => {
|
||||
sortOrder: 'desc',
|
||||
};
|
||||
expect(getters.getFilteredNotifications(state)(filters)).toEqual([
|
||||
{ id: 1, read_at: '2024-02-07T11:42:39.988Z', snoozed_until: null },
|
||||
{ id: 2, read_at: null, snoozed_until: null },
|
||||
{
|
||||
id: 3,
|
||||
read_at: '2024-02-07T11:42:39.988Z',
|
||||
@@ -42,6 +44,16 @@ describe('#getters', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('getNotificationById', () => {
|
||||
const state = {
|
||||
records: {
|
||||
1: { id: 1 },
|
||||
},
|
||||
};
|
||||
expect(getters.getNotificationById(state)(1)).toEqual({ id: 1 });
|
||||
expect(getters.getNotificationById(state)(2)).toEqual({});
|
||||
});
|
||||
|
||||
it('getUIFlags', () => {
|
||||
const state = {
|
||||
uiFlags: {
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
import {
|
||||
filterByStatus,
|
||||
filterByType,
|
||||
filterByTypeAndStatus,
|
||||
applyInboxPageFilters,
|
||||
sortComparator,
|
||||
} from '../../notifications/helpers';
|
||||
import { sortComparator } from '../../notifications/helpers';
|
||||
|
||||
const notifications = [
|
||||
{
|
||||
@@ -45,126 +39,6 @@ const notifications = [
|
||||
},
|
||||
];
|
||||
|
||||
describe('#filterByStatus', () => {
|
||||
it('returns the notifications with snoozed status', () => {
|
||||
const filters = { status: 'snoozed' };
|
||||
notifications.forEach(notification => {
|
||||
expect(
|
||||
filterByStatus(notification.snoozed_until, filters.status)
|
||||
).toEqual(notification.snoozed_until !== null);
|
||||
});
|
||||
});
|
||||
it('returns true if the notification is snoozed', () => {
|
||||
const filters = { status: 'snoozed' };
|
||||
expect(
|
||||
filterByStatus(notifications[3].snoozed_until, filters.status)
|
||||
).toEqual(true);
|
||||
});
|
||||
it('returns false if the notification is not snoozed', () => {
|
||||
const filters = { status: 'snoozed' };
|
||||
expect(
|
||||
filterByStatus(notifications[2].snoozed_until, filters.status)
|
||||
).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#filterByType', () => {
|
||||
it('returns the notifications with read status', () => {
|
||||
const filters = { type: 'read' };
|
||||
notifications.forEach(notification => {
|
||||
expect(filterByType(notification.read_at, filters.type)).toEqual(
|
||||
notification.read_at !== null
|
||||
);
|
||||
});
|
||||
});
|
||||
it('returns true if the notification is read', () => {
|
||||
const filters = { type: 'read' };
|
||||
expect(filterByType(notifications[0].read_at, filters.type)).toEqual(true);
|
||||
});
|
||||
it('returns false if the notification is not read', () => {
|
||||
const filters = { type: 'read' };
|
||||
expect(filterByType(notifications[1].read_at, filters.type)).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#filterByTypeAndStatus', () => {
|
||||
it('returns the notifications with type and status', () => {
|
||||
const filters = { type: 'read', status: 'snoozed' };
|
||||
notifications.forEach(notification => {
|
||||
expect(
|
||||
filterByTypeAndStatus(
|
||||
notification.read_at,
|
||||
notification.snoozed_until,
|
||||
filters.type,
|
||||
filters.status
|
||||
)
|
||||
).toEqual(
|
||||
notification.read_at !== null && notification.snoozed_until !== null
|
||||
);
|
||||
});
|
||||
});
|
||||
it('returns true if the notification is read and snoozed', () => {
|
||||
const filters = { type: 'read', status: 'snoozed' };
|
||||
expect(
|
||||
filterByTypeAndStatus(
|
||||
notifications[4].read_at,
|
||||
notifications[4].snoozed_until,
|
||||
filters.type,
|
||||
filters.status
|
||||
)
|
||||
).toEqual(true);
|
||||
});
|
||||
it('returns false if the notification is not read and snoozed', () => {
|
||||
const filters = { type: 'read', status: 'snoozed' };
|
||||
expect(
|
||||
filterByTypeAndStatus(
|
||||
notifications[3].read_at,
|
||||
notifications[3].snoozed_until,
|
||||
filters.type,
|
||||
filters.status
|
||||
)
|
||||
).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#applyInboxPageFilters', () => {
|
||||
it('returns the notifications with type and status', () => {
|
||||
const filters = { type: 'read', status: 'snoozed' };
|
||||
notifications.forEach(notification => {
|
||||
expect(applyInboxPageFilters(notification, filters)).toEqual(
|
||||
filterByTypeAndStatus(
|
||||
notification.read_at,
|
||||
notification.snoozed_until,
|
||||
filters.type,
|
||||
filters.status
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
it('returns the notifications with type only', () => {
|
||||
const filters = { type: 'read', status: null };
|
||||
notifications.forEach(notification => {
|
||||
expect(applyInboxPageFilters(notification, filters)).toEqual(
|
||||
filterByType(notification.read_at, filters.type)
|
||||
);
|
||||
});
|
||||
});
|
||||
it('returns the notifications with status only', () => {
|
||||
const filters = { type: null, status: 'snoozed' };
|
||||
notifications.forEach(notification => {
|
||||
expect(applyInboxPageFilters(notification, filters)).toEqual(
|
||||
filterByStatus(notification.snoozed_until, filters.status)
|
||||
);
|
||||
});
|
||||
});
|
||||
it('returns true if there are no filters', () => {
|
||||
const filters = { type: null, status: null };
|
||||
notifications.forEach(notification => {
|
||||
expect(applyInboxPageFilters(notification, filters)).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#sortComparator', () => {
|
||||
it('returns the notifications sorted by newest', () => {
|
||||
const sortOrder = 'newest';
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import axios from 'axios';
|
||||
import { actions } from '../../sla';
|
||||
import * as types from '../../../mutation-types';
|
||||
import SLAList from './fixtures';
|
||||
|
||||
const commit = jest.fn();
|
||||
global.axios = axios;
|
||||
jest.mock('axios');
|
||||
|
||||
describe('#actions', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('#get', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.get.mockResolvedValue({
|
||||
data: { payload: SLAList },
|
||||
});
|
||||
await actions.get({ commit });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.default.SET_SLA_UI_FLAG, { isFetching: true }],
|
||||
[types.default.SET_SLA, SLAList],
|
||||
[types.default.SET_SLA_UI_FLAG, { isFetching: false }],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.get.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await actions.get({ commit });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.default.SET_SLA_UI_FLAG, { isFetching: true }],
|
||||
[types.default.SET_SLA_UI_FLAG, { isFetching: false }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#create', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.post.mockResolvedValue({
|
||||
data: { payload: SLAList[0] },
|
||||
});
|
||||
await actions.create({ commit }, SLAList[0]);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.default.SET_SLA_UI_FLAG, { isCreating: true }],
|
||||
[types.default.ADD_SLA, SLAList[0]],
|
||||
[types.default.SET_SLA_UI_FLAG, { isCreating: false }],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.post.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await expect(actions.create({ commit })).rejects.toThrow(Error);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.default.SET_SLA_UI_FLAG, { isCreating: true }],
|
||||
[types.default.SET_SLA_UI_FLAG, { isCreating: false }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#delete', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.delete.mockResolvedValue({});
|
||||
await actions.delete({ commit }, 1);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.default.SET_SLA_UI_FLAG, { isDeleting: true }],
|
||||
[types.default.DELETE_SLA, 1],
|
||||
[types.default.SET_SLA_UI_FLAG, { isDeleting: false }],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.delete.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await expect(actions.delete({ commit })).rejects.toThrow(Error);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.default.SET_SLA_UI_FLAG, { isDeleting: true }],
|
||||
[types.default.SET_SLA_UI_FLAG, { isDeleting: false }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,95 @@
|
||||
export default [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Premium SLA',
|
||||
description:
|
||||
'SLA for chatwoot cloud premium and self-hosted premium customers. SLA for chatwoot cloud premium and self-hosted premium customers',
|
||||
first_response_time_threshold: 14400,
|
||||
next_response_time_threshold: 18000,
|
||||
resolution_time_threshold: 86400,
|
||||
only_during_business_hours: true,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Enterprise SLA',
|
||||
description:
|
||||
'SLA for chatwoot enterprise and self-hosted enterprise customers.',
|
||||
first_response_time_threshold: 600,
|
||||
next_response_time_threshold: 2400,
|
||||
resolution_time_threshold: 3600,
|
||||
only_during_business_hours: false,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Business SLA',
|
||||
description:
|
||||
'Chatwoot cloud Business and self-hosted Business customers SLA',
|
||||
first_response_time_threshold: null,
|
||||
next_response_time_threshold: null,
|
||||
resolution_time_threshold: null,
|
||||
only_during_business_hours: false,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Hacker SLA',
|
||||
description: '',
|
||||
first_response_time_threshold: 60,
|
||||
next_response_time_threshold: 120,
|
||||
resolution_time_threshold: 180,
|
||||
only_during_business_hours: false,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'SLA',
|
||||
description: '',
|
||||
first_response_time_threshold: 120,
|
||||
next_response_time_threshold: 300,
|
||||
resolution_time_threshold: 21600,
|
||||
only_during_business_hours: false,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'ALla',
|
||||
description: '',
|
||||
first_response_time_threshold: 5400,
|
||||
next_response_time_threshold: 9000,
|
||||
resolution_time_threshold: 23040,
|
||||
only_during_business_hours: false,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: '10',
|
||||
description: '',
|
||||
first_response_time_threshold: 120,
|
||||
next_response_time_threshold: null,
|
||||
resolution_time_threshold: null,
|
||||
only_during_business_hours: false,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: '11',
|
||||
description: '',
|
||||
first_response_time_threshold: null,
|
||||
next_response_time_threshold: 240,
|
||||
resolution_time_threshold: null,
|
||||
only_during_business_hours: false,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: '12',
|
||||
description: '',
|
||||
first_response_time_threshold: null,
|
||||
next_response_time_threshold: null,
|
||||
resolution_time_threshold: 300,
|
||||
only_during_business_hours: false,
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: '14',
|
||||
description: '',
|
||||
first_response_time_threshold: null,
|
||||
next_response_time_threshold: null,
|
||||
resolution_time_threshold: null,
|
||||
only_during_business_hours: false,
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,26 @@
|
||||
import { getters } from '../../sla';
|
||||
import SLAs from './fixtures';
|
||||
|
||||
describe('#getters', () => {
|
||||
it('getSLA', () => {
|
||||
const state = { records: SLAs };
|
||||
expect(getters.getSLA(state)).toEqual(SLAs);
|
||||
});
|
||||
|
||||
it('getUIFlags', () => {
|
||||
const state = {
|
||||
uiFlags: {
|
||||
isFetching: true,
|
||||
isCreating: false,
|
||||
isUpdating: false,
|
||||
isDeleting: false,
|
||||
},
|
||||
};
|
||||
expect(getters.getUIFlags(state)).toEqual({
|
||||
isFetching: true,
|
||||
isCreating: false,
|
||||
isUpdating: false,
|
||||
isDeleting: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
import types from '../../../mutation-types';
|
||||
import { mutations } from '../../sla';
|
||||
import SLAs from './fixtures';
|
||||
|
||||
describe('#mutations', () => {
|
||||
describe('#SET_SLA_UI_FLAG', () => {
|
||||
it('set sla ui flags', () => {
|
||||
const state = { uiFlags: {} };
|
||||
mutations[types.SET_SLA_UI_FLAG](state, { isFetching: true });
|
||||
expect(state.uiFlags).toEqual({ isFetching: true });
|
||||
});
|
||||
});
|
||||
describe('#SET_SLA', () => {
|
||||
it('set sla records', () => {
|
||||
const state = { records: [] };
|
||||
mutations[types.SET_SLA](state, SLAs);
|
||||
expect(state.records).toEqual(SLAs);
|
||||
});
|
||||
});
|
||||
describe('#ADD_SLA', () => {
|
||||
it('push newly created sla to the store', () => {
|
||||
const state = { records: [SLAs[0]] };
|
||||
mutations[types.ADD_SLA](state, SLAs[1]);
|
||||
expect(state.records).toEqual([SLAs[0], SLAs[1]]);
|
||||
});
|
||||
});
|
||||
describe('#DELETE_SLA', () => {
|
||||
it('delete sla record', () => {
|
||||
const state = { records: [SLAs[0]] };
|
||||
mutations[types.DELETE_SLA](state, 1);
|
||||
expect(state.records).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import axios from 'axios';
|
||||
import { actions } from '../../SLAReports';
|
||||
import appliedSlas from './fixtures';
|
||||
import types from '../../../mutation-types';
|
||||
|
||||
const commit = jest.fn();
|
||||
global.axios = axios;
|
||||
jest.mock('axios');
|
||||
|
||||
describe('#actions', () => {
|
||||
describe('#get', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.get.mockResolvedValue({
|
||||
data: { payload: appliedSlas, meta: { count: 1 } },
|
||||
});
|
||||
await actions.get({ commit }, {});
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_SLA_REPORTS_UI_FLAG, { isFetching: true }],
|
||||
[types.SET_SLA_REPORTS, appliedSlas],
|
||||
[types.SET_SLA_REPORTS_META, { count: 1 }],
|
||||
[types.SET_SLA_REPORTS_UI_FLAG, { isFetching: false }],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.get.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await expect(actions.get({ commit }, { teamId: 1 })).rejects.toThrow(
|
||||
Error
|
||||
);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_SLA_REPORTS_UI_FLAG, { isFetching: true }],
|
||||
[types.SET_SLA_REPORTS_UI_FLAG, { isFetching: false }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getMetrics', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.get.mockResolvedValue({ data: { metrics: { count: 1 } } });
|
||||
await actions.getMetrics({ commit }, {});
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_SLA_REPORTS_UI_FLAG, { isFetchingMetrics: true }],
|
||||
[types.SET_SLA_REPORTS_METRICS, { metrics: { count: 1 } }],
|
||||
[types.SET_SLA_REPORTS_UI_FLAG, { isFetchingMetrics: false }],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.get.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await actions.getMetrics({ commit }, { teamId: 1 });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_SLA_REPORTS_UI_FLAG, { isFetchingMetrics: true }],
|
||||
[types.SET_SLA_REPORTS_UI_FLAG, { isFetchingMetrics: false }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,52 @@
|
||||
export default [
|
||||
{
|
||||
id: 23,
|
||||
sla_policy_id: 7,
|
||||
conversation_id: 152,
|
||||
sla_status: 'active_with_misses',
|
||||
created_at: '2024-03-31T07:50:53.518Z',
|
||||
updated_at: '2024-03-31T07:55:06.451Z',
|
||||
conversation: {
|
||||
id: 152,
|
||||
uuid: '2f9a988d-418f-47d9-b4dc-c441f28da7c2',
|
||||
account_id: 1,
|
||||
},
|
||||
sla_events: [
|
||||
{
|
||||
id: 14,
|
||||
event_type: 'frt',
|
||||
meta: {},
|
||||
updated_at: 1711871706,
|
||||
created_at: 1711871706,
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
event_type: 'rt',
|
||||
meta: {},
|
||||
updated_at: 1711871706,
|
||||
created_at: 1711871706,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 24,
|
||||
sla_policy_id: 7,
|
||||
conversation_id: 153,
|
||||
sla_status: 'active_with_misses',
|
||||
created_at: '2024-03-31T07:57:49.659Z',
|
||||
updated_at: '2024-03-31T08:00:31.627Z',
|
||||
conversation: {
|
||||
id: 153,
|
||||
uuid: 'd5d97961-4341-469e-accf-f13f25a14c3c',
|
||||
},
|
||||
sla_events: [
|
||||
{
|
||||
id: 16,
|
||||
event_type: 'rt',
|
||||
meta: {},
|
||||
updated_at: 1711872031,
|
||||
created_at: 1711872031,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,53 @@
|
||||
import { getters } from '../../SLAReports';
|
||||
import appliedSlas from './fixtures';
|
||||
|
||||
describe('#getters', () => {
|
||||
it('getAppliedSlas', () => {
|
||||
const state = {
|
||||
records: [appliedSlas[0]],
|
||||
};
|
||||
expect(getters.getAll(state)).toEqual([appliedSlas[0]]);
|
||||
});
|
||||
|
||||
it('getUIFlags', () => {
|
||||
const state = {
|
||||
uiFlags: {
|
||||
isFetching: false,
|
||||
isFetchingMetrics: false,
|
||||
},
|
||||
};
|
||||
expect(getters.getUIFlags(state)).toEqual({
|
||||
isFetching: false,
|
||||
isFetchingMetrics: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('getMeta', () => {
|
||||
const state = {
|
||||
meta: {
|
||||
count: 0,
|
||||
currentPage: 1,
|
||||
},
|
||||
};
|
||||
expect(getters.getMeta(state)).toEqual({
|
||||
count: 0,
|
||||
currentPage: 1,
|
||||
});
|
||||
});
|
||||
|
||||
it('getMetrics', () => {
|
||||
const state = {
|
||||
metrics: {
|
||||
numberOfConversations: 27,
|
||||
numberOfSLAMisses: 25,
|
||||
hitRate: '7.41%',
|
||||
},
|
||||
};
|
||||
|
||||
expect(getters.getMetrics(state)).toEqual({
|
||||
numberOfConversations: 27,
|
||||
numberOfSLAMisses: 25,
|
||||
hitRate: '7.41%',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
import { mutations } from '../../SLAReports';
|
||||
import appliedSlas from './fixtures';
|
||||
import types from '../../../mutation-types';
|
||||
|
||||
describe('#mutations', () => {
|
||||
describe('#SET_SLA_REPORTS', () => {
|
||||
it('Adds sla reports', () => {
|
||||
const state = { records: {} };
|
||||
mutations[types.SET_SLA_REPORTS](state, appliedSlas);
|
||||
expect(state.records).toEqual(appliedSlas);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#SET_SLA_REPORTS_UI_FLAG', () => {
|
||||
it('set ui flags', () => {
|
||||
const state = { uiFlags: {} };
|
||||
mutations[types.SET_SLA_REPORTS_UI_FLAG](state, { isFetching: true });
|
||||
expect(state.uiFlags).toEqual({ isFetching: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('#SET_SLA_REPORTS_METRICS', () => {
|
||||
it('set metrics', () => {
|
||||
const state = { metrics: {} };
|
||||
mutations[types.SET_SLA_REPORTS_METRICS](state, {
|
||||
number_of_sla_misses: 1,
|
||||
hit_rate: '100%',
|
||||
total_applied_slas: 1,
|
||||
});
|
||||
expect(state.metrics).toEqual({
|
||||
numberOfSLAMisses: 1,
|
||||
hitRate: '100%',
|
||||
numberOfConversations: 1,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#SET_SLA_REPORTS_META', () => {
|
||||
it('set meta', () => {
|
||||
const state = { meta: {} };
|
||||
mutations[types.SET_SLA_REPORTS_META](state, {
|
||||
count: 1,
|
||||
current_page: 1,
|
||||
});
|
||||
expect(state.meta).toEqual({
|
||||
count: 1,
|
||||
currentPage: 1,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user