Initial commit: Add logistics and order_detail message types
Some checks failed
Lock Threads / action (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot EE docker images / merge (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot CE docker images / merge (push) Has been cancelled
Run Chatwoot CE spec / lint-backend (push) Has been cancelled
Run Chatwoot CE spec / lint-frontend (push) Has been cancelled
Run Chatwoot CE spec / frontend-tests (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (0, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (1, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (10, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (11, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (12, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (13, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (14, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (15, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (2, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (3, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (4, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (5, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (6, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (7, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (8, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (9, 16) (push) Has been cancelled
Run Linux nightly installer / nightly (push) Has been cancelled
Some checks failed
Lock Threads / action (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot EE docker images / merge (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot CE docker images / merge (push) Has been cancelled
Run Chatwoot CE spec / lint-backend (push) Has been cancelled
Run Chatwoot CE spec / lint-frontend (push) Has been cancelled
Run Chatwoot CE spec / frontend-tests (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (0, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (1, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (10, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (11, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (12, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (13, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (14, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (15, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (2, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (3, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (4, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (5, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (6, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (7, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (8, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (9, 16) (push) Has been cancelled
Run Linux nightly installer / nightly (push) Has been cancelled
- Add Logistics component with progress tracking - Add OrderDetail component for order information - Support data-driven steps and actions - Add blue color scale to widget SCSS - Fix node overflow and progress bar rendering issues - Add English translations for dashboard components Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
import PortalAPI from 'dashboard/api/helpCenter/portals';
|
||||
import { throwErrorMessage } from 'dashboard/store/utils/api';
|
||||
import { types } from './mutations';
|
||||
const portalAPIs = new PortalAPI();
|
||||
|
||||
export const actions = {
|
||||
index: async ({ commit }) => {
|
||||
try {
|
||||
commit(types.SET_UI_FLAG, { isFetching: true });
|
||||
const {
|
||||
data: { payload },
|
||||
} = await portalAPIs.get();
|
||||
commit(types.CLEAR_PORTALS);
|
||||
const portalSlugs = payload.map(portal => portal.slug);
|
||||
commit(types.ADD_MANY_PORTALS_ENTRY, payload);
|
||||
commit(types.ADD_MANY_PORTALS_IDS, portalSlugs);
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_UI_FLAG, { isFetching: false });
|
||||
}
|
||||
},
|
||||
|
||||
show: async ({ commit }, { portalSlug, locale }) => {
|
||||
commit(types.SET_UI_FLAG, { isFetchingItem: true });
|
||||
try {
|
||||
const response = await portalAPIs.getPortal({ portalSlug, locale });
|
||||
const {
|
||||
data: { meta },
|
||||
} = response;
|
||||
commit(types.SET_PORTALS_META, meta);
|
||||
} catch (error) {
|
||||
// Ignore error
|
||||
} finally {
|
||||
commit(types.SET_UI_FLAG, { isFetchingItem: false });
|
||||
}
|
||||
},
|
||||
|
||||
create: async ({ commit }, params) => {
|
||||
commit(types.SET_UI_FLAG, { isCreating: true });
|
||||
try {
|
||||
const { data } = await portalAPIs.create(params);
|
||||
const { slug: portalSlug } = data;
|
||||
commit(types.ADD_PORTAL_ENTRY, data);
|
||||
commit(types.ADD_PORTAL_ID, portalSlug);
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_UI_FLAG, { isCreating: false });
|
||||
}
|
||||
},
|
||||
|
||||
update: async ({ commit }, { portalSlug, ...portalObj }) => {
|
||||
commit(types.SET_HELP_PORTAL_UI_FLAG, {
|
||||
uiFlags: { isUpdating: true },
|
||||
portalSlug,
|
||||
});
|
||||
try {
|
||||
const { data } = await portalAPIs.updatePortal({
|
||||
portalSlug,
|
||||
portalObj,
|
||||
});
|
||||
commit(types.UPDATE_PORTAL_ENTRY, data);
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_HELP_PORTAL_UI_FLAG, {
|
||||
uiFlags: { isUpdating: false },
|
||||
portalSlug,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
delete: async ({ commit }, { portalSlug }) => {
|
||||
commit(types.SET_HELP_PORTAL_UI_FLAG, {
|
||||
uiFlags: { isDeleting: true },
|
||||
portalSlug,
|
||||
});
|
||||
try {
|
||||
await portalAPIs.delete(portalSlug);
|
||||
commit(types.REMOVE_PORTAL_ENTRY, portalSlug);
|
||||
commit(types.REMOVE_PORTAL_ID, portalSlug);
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_HELP_PORTAL_UI_FLAG, {
|
||||
uiFlags: { isDeleting: false },
|
||||
portalSlug,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
deleteLogo: async ({ commit }, { portalSlug }) => {
|
||||
commit(types.SET_HELP_PORTAL_UI_FLAG, {
|
||||
uiFlags: { isUpdating: true },
|
||||
portalSlug,
|
||||
});
|
||||
try {
|
||||
await portalAPIs.deleteLogo(portalSlug);
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_HELP_PORTAL_UI_FLAG, {
|
||||
uiFlags: { isUpdating: false },
|
||||
portalSlug,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
updatePortal: async ({ commit }, portal) => {
|
||||
commit(types.UPDATE_PORTAL_ENTRY, portal);
|
||||
},
|
||||
|
||||
switchPortal: async ({ commit }, isSwitching) => {
|
||||
commit(types.SET_PORTAL_SWITCHING_FLAG, {
|
||||
isSwitching,
|
||||
});
|
||||
},
|
||||
|
||||
sendCnameInstructions: async (_, { portalSlug, email }) => {
|
||||
try {
|
||||
await portalAPIs.sendCnameInstructions(portalSlug, email);
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
}
|
||||
},
|
||||
|
||||
sslStatus: async ({ commit }, { portalSlug }) => {
|
||||
try {
|
||||
commit(types.SET_UI_FLAG, { isFetchingSSLStatus: true });
|
||||
const { data } = await portalAPIs.sslStatus(portalSlug);
|
||||
commit(types.SET_SSL_SETTINGS, { portalSlug, sslSettings: data });
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
commit(types.SET_UI_FLAG, { isFetchingSSLStatus: false });
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
export const getters = {
|
||||
uiFlagsIn: state => portalId => {
|
||||
const uiFlags = state.portals.uiFlags.byId[portalId];
|
||||
if (uiFlags) return uiFlags;
|
||||
return { isFetching: false, isUpdating: false, isDeleting: false };
|
||||
},
|
||||
|
||||
isFetchingPortals: state => state.uiFlags.isFetching,
|
||||
isCreatingPortal: state => state.uiFlags.isCreating,
|
||||
isSwitchingPortal: state => state.uiFlags.isSwitching,
|
||||
isFetchingSSLStatus: state => state.uiFlags.isFetchingSSLStatus,
|
||||
portalBySlug:
|
||||
(...getterArguments) =>
|
||||
portalId => {
|
||||
const [state] = getterArguments;
|
||||
const portal = state.portals.byId[portalId];
|
||||
|
||||
return portal;
|
||||
},
|
||||
allPortals: (...getterArguments) => {
|
||||
const [state, _getters] = getterArguments;
|
||||
const portals = state.portals.allIds.map(id => {
|
||||
return _getters.portalBySlug(id);
|
||||
});
|
||||
return portals;
|
||||
},
|
||||
count: state => state.portals.allIds.length || 0,
|
||||
getMeta: state => state.meta,
|
||||
isSwitching: state => state.isSwitching,
|
||||
};
|
||||
45
app/javascript/dashboard/store/modules/helpCenterPortals/index.js
Executable file
45
app/javascript/dashboard/store/modules/helpCenterPortals/index.js
Executable file
@@ -0,0 +1,45 @@
|
||||
import { getters } from './getters';
|
||||
import { actions } from './actions';
|
||||
import { mutations } from './mutations';
|
||||
|
||||
export const defaultPortalFlags = {
|
||||
isFetching: false,
|
||||
isUpdating: false,
|
||||
isDeleting: false,
|
||||
isFetchingSSLStatus: false,
|
||||
};
|
||||
|
||||
const state = {
|
||||
meta: {
|
||||
allArticlesCount: 0,
|
||||
mineArticlesCount: 0,
|
||||
draftArticlesCount: 0,
|
||||
archivedArticlesCount: 0,
|
||||
},
|
||||
|
||||
portals: {
|
||||
byId: {},
|
||||
allIds: [],
|
||||
uiFlags: {
|
||||
byId: {
|
||||
// 1: { isFetching: false, isUpdating: false, isDeleting: false },
|
||||
},
|
||||
},
|
||||
meta: {
|
||||
byId: {},
|
||||
},
|
||||
},
|
||||
uiFlags: {
|
||||
allFetched: false,
|
||||
isFetching: false,
|
||||
isSwitching: false,
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
getters,
|
||||
actions,
|
||||
mutations,
|
||||
};
|
||||
@@ -0,0 +1,128 @@
|
||||
import { defaultPortalFlags } from './index';
|
||||
|
||||
export const types = {
|
||||
SET_UI_FLAG: 'setUIFlag',
|
||||
ADD_PORTAL_ENTRY: 'addPortalEntry',
|
||||
SET_PORTALS_META: 'setPortalsMeta',
|
||||
ADD_MANY_PORTALS_ENTRY: 'addManyPortalsEntry',
|
||||
ADD_PORTAL_ID: 'addPortalId',
|
||||
CLEAR_PORTALS: 'clearPortals',
|
||||
ADD_MANY_PORTALS_IDS: 'addManyPortalsIds',
|
||||
UPDATE_PORTAL_ENTRY: 'updatePortalEntry',
|
||||
REMOVE_PORTAL_ENTRY: 'removePortalEntry',
|
||||
REMOVE_PORTAL_ID: 'removePortalId',
|
||||
SET_HELP_PORTAL_UI_FLAG: 'setHelpCenterUIFlag',
|
||||
SET_PORTAL_SWITCHING_FLAG: 'setPortalSwitchingFlag',
|
||||
SET_SSL_SETTINGS: 'setSSLSettings',
|
||||
};
|
||||
|
||||
export const mutations = {
|
||||
[types.SET_UI_FLAG]($state, uiFlags) {
|
||||
$state.uiFlags = {
|
||||
...$state.uiFlags,
|
||||
...uiFlags,
|
||||
};
|
||||
},
|
||||
|
||||
[types.ADD_PORTAL_ENTRY]($state, portal) {
|
||||
$state.portals.byId = {
|
||||
...$state.portals.byId,
|
||||
[portal.slug]: {
|
||||
...portal,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
[types.ADD_MANY_PORTALS_ENTRY]($state, portals) {
|
||||
const allPortals = { ...$state.portals.byId };
|
||||
portals.forEach(portal => {
|
||||
allPortals[portal.slug] = portal;
|
||||
});
|
||||
$state.portals.byId = allPortals;
|
||||
},
|
||||
|
||||
[types.CLEAR_PORTALS]: $state => {
|
||||
$state.portals.byId = {};
|
||||
$state.portals.allIds = [];
|
||||
$state.portals.uiFlags.byId = {};
|
||||
},
|
||||
|
||||
[types.SET_PORTALS_META]: ($state, data) => {
|
||||
const {
|
||||
all_articles_count: allArticlesCount = 0,
|
||||
mine_articles_count: mineArticlesCount = 0,
|
||||
draft_articles_count: draftArticlesCount = 0,
|
||||
archived_articles_count: archivedArticlesCount = 0,
|
||||
} = data;
|
||||
$state.meta = {
|
||||
...$state.meta,
|
||||
allArticlesCount,
|
||||
archivedArticlesCount,
|
||||
mineArticlesCount,
|
||||
draftArticlesCount,
|
||||
};
|
||||
},
|
||||
|
||||
[types.ADD_PORTAL_ID]($state, portalSlug) {
|
||||
$state.portals.allIds.push(portalSlug);
|
||||
},
|
||||
|
||||
[types.ADD_MANY_PORTALS_IDS]($state, portalSlugs) {
|
||||
$state.portals.allIds.push(...portalSlugs);
|
||||
},
|
||||
|
||||
[types.UPDATE_PORTAL_ENTRY]($state, portal) {
|
||||
const portalSlug = portal.slug;
|
||||
if (!$state.portals.allIds.includes(portalSlug)) return;
|
||||
|
||||
$state.portals.byId = {
|
||||
...$state.portals.byId,
|
||||
[portalSlug]: {
|
||||
...portal,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
[types.REMOVE_PORTAL_ENTRY]($state, portalSlug) {
|
||||
if (!portalSlug) return;
|
||||
|
||||
const { [portalSlug]: toBeRemoved, ...newById } = $state.portals.byId;
|
||||
$state.portals.byId = newById;
|
||||
},
|
||||
|
||||
[types.REMOVE_PORTAL_ID]($state, portalSlug) {
|
||||
$state.portals.allIds = $state.portals.allIds.filter(
|
||||
slug => slug !== portalSlug
|
||||
);
|
||||
},
|
||||
|
||||
[types.SET_HELP_PORTAL_UI_FLAG]($state, { portalSlug, uiFlags }) {
|
||||
const flags = $state.portals.uiFlags.byId[portalSlug];
|
||||
$state.portals.uiFlags.byId = {
|
||||
...$state.portals.uiFlags.byId,
|
||||
[portalSlug]: {
|
||||
...defaultPortalFlags,
|
||||
...flags,
|
||||
...uiFlags,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
[types.SET_PORTAL_SWITCHING_FLAG]($state, { isSwitching }) {
|
||||
$state.uiFlags.isSwitching = isSwitching;
|
||||
},
|
||||
|
||||
[types.SET_SSL_SETTINGS]($state, { portalSlug, sslSettings }) {
|
||||
const portal = $state.portals.byId[portalSlug];
|
||||
$state.portals.byId = {
|
||||
...$state.portals.byId,
|
||||
[portalSlug]: {
|
||||
...portal,
|
||||
ssl_settings: {
|
||||
...portal.ssl_settings,
|
||||
...sslSettings,
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,202 @@
|
||||
import axios from 'axios';
|
||||
import { actions } from '../actions';
|
||||
import { types } from '../mutations';
|
||||
import { apiResponse } from './fixtures';
|
||||
|
||||
const commit = vi.fn();
|
||||
const dispatch = vi.fn();
|
||||
global.axios = axios;
|
||||
vi.mock('axios');
|
||||
|
||||
describe('#actions', () => {
|
||||
describe('#index', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.get.mockResolvedValue({ data: apiResponse });
|
||||
await actions.index({
|
||||
commit,
|
||||
dispatch,
|
||||
state: {},
|
||||
});
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_UI_FLAG, { isFetching: true }],
|
||||
[types.CLEAR_PORTALS],
|
||||
[types.ADD_MANY_PORTALS_ENTRY, apiResponse.payload],
|
||||
[types.ADD_MANY_PORTALS_IDS, ['domain', 'campaign']],
|
||||
[types.SET_UI_FLAG, { isFetching: false }],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.get.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await expect(actions.index({ commit })).rejects.toThrow(Error);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_UI_FLAG, { isFetching: true }],
|
||||
[types.SET_UI_FLAG, { isFetching: false }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#create', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.post.mockResolvedValue({ data: apiResponse.payload[1] });
|
||||
await actions.create(
|
||||
{ commit, dispatch, state: { portals: {} } },
|
||||
{
|
||||
color: 'red',
|
||||
custom_domain: 'domain_for_help',
|
||||
header_text: 'Domain Header',
|
||||
}
|
||||
);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_UI_FLAG, { isCreating: true }],
|
||||
[types.ADD_PORTAL_ENTRY, apiResponse.payload[1]],
|
||||
[types.ADD_PORTAL_ID, 'campaign'],
|
||||
[types.SET_UI_FLAG, { isCreating: false }],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.post.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await expect(
|
||||
actions.create({ commit, dispatch, state: { portals: {} } }, {})
|
||||
).rejects.toThrow(Error);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_UI_FLAG, { isCreating: true }],
|
||||
[types.SET_UI_FLAG, { isCreating: false }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#show', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.get.mockResolvedValue({
|
||||
data: { meta: { all_articles_count: 1 } },
|
||||
});
|
||||
await actions.show(
|
||||
{ commit },
|
||||
{
|
||||
portalSlug: 'handbook',
|
||||
locale: 'en',
|
||||
}
|
||||
);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_UI_FLAG, { isFetchingItem: true }],
|
||||
[types.SET_PORTALS_META, { all_articles_count: 1 }],
|
||||
[types.SET_UI_FLAG, { isFetchingItem: false }],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.post.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await expect(
|
||||
actions.create({ commit, dispatch, state: { portals: {} } }, {})
|
||||
).rejects.toThrow(Error);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_UI_FLAG, { isCreating: true }],
|
||||
[types.SET_UI_FLAG, { isCreating: false }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#update', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.patch.mockResolvedValue({ data: apiResponse.payload[1] });
|
||||
await actions.update(
|
||||
{ commit },
|
||||
{ portalObj: apiResponse.payload[1], portalSlug: 'campaign' }
|
||||
);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[
|
||||
types.SET_HELP_PORTAL_UI_FLAG,
|
||||
{ uiFlags: { isUpdating: true }, portalSlug: 'campaign' },
|
||||
],
|
||||
[types.UPDATE_PORTAL_ENTRY, apiResponse.payload[1]],
|
||||
[
|
||||
types.SET_HELP_PORTAL_UI_FLAG,
|
||||
{ uiFlags: { isUpdating: false }, portalSlug: 'campaign' },
|
||||
],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.patch.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await expect(
|
||||
actions.update(
|
||||
{ commit },
|
||||
{ portalObj: apiResponse.payload[1], portalSlug: 'campaign' }
|
||||
)
|
||||
).rejects.toThrow(Error);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[
|
||||
types.SET_HELP_PORTAL_UI_FLAG,
|
||||
{ uiFlags: { isUpdating: true }, portalSlug: 'campaign' },
|
||||
],
|
||||
[
|
||||
types.SET_HELP_PORTAL_UI_FLAG,
|
||||
{ uiFlags: { isUpdating: false }, portalSlug: 'campaign' },
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#sslStatus', () => {
|
||||
it('commits SET_SSL_SETTINGS with data from API', async () => {
|
||||
axios.get.mockResolvedValue({
|
||||
data: { status: 'active', verification_errors: [] },
|
||||
});
|
||||
await actions.sslStatus({ commit }, { portalSlug: 'domain' });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_UI_FLAG, { isFetchingSSLStatus: true }],
|
||||
[
|
||||
types.SET_SSL_SETTINGS,
|
||||
{
|
||||
portalSlug: 'domain',
|
||||
sslSettings: { status: 'active', verification_errors: [] },
|
||||
},
|
||||
],
|
||||
[types.SET_UI_FLAG, { isFetchingSSLStatus: false }],
|
||||
]);
|
||||
});
|
||||
it('throws error and does not commit when API fails', async () => {
|
||||
axios.get.mockRejectedValue({ message: 'error' });
|
||||
await expect(
|
||||
actions.sslStatus({ commit }, { portalSlug: 'domain' })
|
||||
).rejects.toThrow(Error);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_UI_FLAG, { isFetchingSSLStatus: true }],
|
||||
[types.SET_UI_FLAG, { isFetchingSSLStatus: false }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#delete', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.delete.mockResolvedValue({});
|
||||
await actions.delete({ commit }, { portalSlug: 'campaign' });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[
|
||||
types.SET_HELP_PORTAL_UI_FLAG,
|
||||
{ uiFlags: { isDeleting: true }, portalSlug: 'campaign' },
|
||||
],
|
||||
[types.REMOVE_PORTAL_ENTRY, 'campaign'],
|
||||
[types.REMOVE_PORTAL_ID, 'campaign'],
|
||||
[
|
||||
types.SET_HELP_PORTAL_UI_FLAG,
|
||||
{ uiFlags: { isDeleting: false }, portalSlug: 'campaign' },
|
||||
],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.delete.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await expect(
|
||||
actions.delete({ commit }, { portalSlug: 'campaign' })
|
||||
).rejects.toThrow(Error);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[
|
||||
types.SET_HELP_PORTAL_UI_FLAG,
|
||||
{ uiFlags: { isDeleting: true }, portalSlug: 'campaign' },
|
||||
],
|
||||
[
|
||||
types.SET_HELP_PORTAL_UI_FLAG,
|
||||
{ uiFlags: { isDeleting: false }, portalSlug: 'campaign' },
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,85 @@
|
||||
export default {
|
||||
meta: {
|
||||
count: 0,
|
||||
currentPage: 1,
|
||||
},
|
||||
portals: {
|
||||
byId: {
|
||||
1: {
|
||||
id: 1,
|
||||
color: 'red',
|
||||
custom_domain: 'domain_for_help',
|
||||
header_text: 'Domain Header',
|
||||
homepage_link: 'help-center',
|
||||
name: 'help name',
|
||||
page_title: 'page title',
|
||||
slug: 'domain',
|
||||
archived: false,
|
||||
config: {
|
||||
allowed_locales: ['en'],
|
||||
},
|
||||
},
|
||||
2: {
|
||||
id: 2,
|
||||
color: 'green',
|
||||
custom_domain: 'campaign_for_help',
|
||||
header_text: 'Campaign Header',
|
||||
homepage_link: 'help-center',
|
||||
name: 'help name',
|
||||
page_title: 'campaign title',
|
||||
slug: 'campaign',
|
||||
archived: false,
|
||||
config: {
|
||||
allowed_locales: ['en'],
|
||||
},
|
||||
},
|
||||
},
|
||||
allIds: [1, 2],
|
||||
uiFlags: {
|
||||
byId: {
|
||||
1: { isFetching: false, isUpdating: true, isDeleting: false },
|
||||
},
|
||||
},
|
||||
},
|
||||
uiFlags: {
|
||||
allFetched: false,
|
||||
isFetching: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const apiResponse = {
|
||||
payload: [
|
||||
{
|
||||
id: 1,
|
||||
color: 'red',
|
||||
custom_domain: 'domain_for_help',
|
||||
header_text: 'Domain Header',
|
||||
homepage_link: 'help-center',
|
||||
name: 'help name',
|
||||
page_title: 'page title',
|
||||
slug: 'domain',
|
||||
archived: false,
|
||||
config: {
|
||||
allowed_locales: ['en'],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
color: 'green',
|
||||
custom_domain: 'campaign_for_help',
|
||||
header_text: 'Campaign Header',
|
||||
homepage_link: 'help-center',
|
||||
name: 'help name',
|
||||
page_title: 'campaign title',
|
||||
slug: 'campaign',
|
||||
archived: false,
|
||||
config: {
|
||||
allowed_locales: ['en'],
|
||||
},
|
||||
},
|
||||
],
|
||||
meta: {
|
||||
current_page: 1,
|
||||
portals_count: 1,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
import { getters } from '../getters';
|
||||
import portal from './fixtures';
|
||||
|
||||
describe('#getters', () => {
|
||||
it('getUIFlagsIn', () => {
|
||||
const state = portal;
|
||||
expect(getters.uiFlagsIn(state)(1)).toEqual({
|
||||
isFetching: false,
|
||||
isUpdating: true,
|
||||
isDeleting: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('isFetchingPortals', () => {
|
||||
const state = portal;
|
||||
expect(getters.isFetchingPortals(state)).toEqual(true);
|
||||
});
|
||||
|
||||
it('portalBySlug', () => {
|
||||
const state = portal;
|
||||
expect(getters.portalBySlug(state)(1)).toEqual({
|
||||
id: 1,
|
||||
color: 'red',
|
||||
custom_domain: 'domain_for_help',
|
||||
header_text: 'Domain Header',
|
||||
homepage_link: 'help-center',
|
||||
name: 'help name',
|
||||
page_title: 'page title',
|
||||
slug: 'domain',
|
||||
archived: false,
|
||||
config: {
|
||||
allowed_locales: ['en'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('allPortals', () => {
|
||||
const state = portal;
|
||||
expect(getters.allPortals(state, getters).length).toEqual(2);
|
||||
});
|
||||
it('count', () => {
|
||||
const state = portal;
|
||||
expect(getters.count(state)).toEqual(2);
|
||||
});
|
||||
|
||||
it('getMeta', () => {
|
||||
const state = portal;
|
||||
expect(getters.getMeta(state)).toEqual({ count: 0, currentPage: 1 });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,146 @@
|
||||
import { mutations, types } from '../mutations';
|
||||
import portal from './fixtures';
|
||||
|
||||
describe('#mutations', () => {
|
||||
let state = {};
|
||||
beforeEach(() => {
|
||||
state = { ...portal };
|
||||
});
|
||||
|
||||
describe('#SET_UI_FLAG', () => {
|
||||
it('It returns default flags if empty object passed', () => {
|
||||
mutations[types.SET_UI_FLAG](state, {});
|
||||
expect(state.uiFlags).toEqual({
|
||||
allFetched: false,
|
||||
isFetching: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('It updates keys when passed as parameters', () => {
|
||||
mutations[types.SET_UI_FLAG](state, { isFetching: false });
|
||||
expect(state.uiFlags).toEqual({
|
||||
allFetched: false,
|
||||
isFetching: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('[types.ADD_PORTAL_ENTRY]', () => {
|
||||
it('does not add empty objects to state', () => {
|
||||
mutations[types.ADD_PORTAL_ENTRY](state, {});
|
||||
expect(state).toEqual(portal);
|
||||
});
|
||||
it('does adds helpcenter object to state', () => {
|
||||
mutations[types.ADD_PORTAL_ENTRY](state, { slug: 'new' });
|
||||
expect(state.portals.byId.new).toEqual({ slug: 'new' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('[types.ADD_PORTAL_ID]', () => {
|
||||
it('adds helpcenter slug to state', () => {
|
||||
mutations[types.ADD_PORTAL_ID](state, 12);
|
||||
expect(state.portals.allIds).toEqual([1, 2, 12]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('[types.UPDATE_PORTAL_ENTRY]', () => {
|
||||
it('does not updates if empty object is passed', () => {
|
||||
mutations[types.UPDATE_PORTAL_ENTRY](state, {});
|
||||
expect(state).toEqual(portal);
|
||||
});
|
||||
it('does not updates if object slug is not present ', () => {
|
||||
mutations[types.UPDATE_PORTAL_ENTRY](state, { slug: 5 });
|
||||
expect(state).toEqual(portal);
|
||||
});
|
||||
it(' updates if object with slug already present in the state', () => {
|
||||
mutations[types.UPDATE_PORTAL_ENTRY](state, {
|
||||
slug: 2,
|
||||
name: 'Updated name',
|
||||
});
|
||||
expect(state.portals.byId[2].name).toEqual('Updated name');
|
||||
});
|
||||
});
|
||||
|
||||
describe('[types.REMOVE_PORTAL_ENTRY]', () => {
|
||||
it('does not remove object entry if no slug is passed', () => {
|
||||
mutations[types.REMOVE_PORTAL_ENTRY](state, undefined);
|
||||
expect(state).toEqual({ ...portal });
|
||||
});
|
||||
it('removes object entry with to conversation if outgoing', () => {
|
||||
mutations[types.REMOVE_PORTAL_ENTRY](state, 2);
|
||||
expect(state.portals.byId[2]).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('[types.REMOVE_PORTAL_ID]', () => {
|
||||
it('removes slug from state', () => {
|
||||
mutations[types.REMOVE_PORTAL_ID](state, 2);
|
||||
expect(state.portals.allIds).toEqual([1, 12]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('[types.SET_HELP_PORTAL_UI_FLAG]', () => {
|
||||
it('sets correct flag in state', () => {
|
||||
mutations[types.SET_HELP_PORTAL_UI_FLAG](state, {
|
||||
portalSlug: 'domain',
|
||||
uiFlags: { isFetching: true },
|
||||
});
|
||||
expect(state.portals.uiFlags.byId.domain).toEqual({
|
||||
isFetching: true,
|
||||
isUpdating: false,
|
||||
isDeleting: false,
|
||||
isFetchingSSLStatus: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('[types.SET_SSL_SETTINGS]', () => {
|
||||
it('merges new ssl settings into existing portal.ssl_settings', () => {
|
||||
state.portals.byId.domain = {
|
||||
slug: 'domain',
|
||||
ssl_settings: { cf_status: 'pending' },
|
||||
};
|
||||
mutations[types.SET_SSL_SETTINGS](state, {
|
||||
portalSlug: 'domain',
|
||||
sslSettings: { status: 'active', verification_errors: ['error'] },
|
||||
});
|
||||
expect(state.portals.byId.domain.ssl_settings).toEqual({
|
||||
cf_status: 'pending',
|
||||
status: 'active',
|
||||
verification_errors: ['error'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#CLEAR_PORTALS', () => {
|
||||
it('clears portals', () => {
|
||||
mutations[types.CLEAR_PORTALS](state);
|
||||
expect(state.portals.allIds).toEqual([]);
|
||||
expect(state.portals.byId).toEqual({});
|
||||
expect(state.portals.uiFlags).toEqual({
|
||||
byId: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#SET_PORTALS_META', () => {
|
||||
it('add meta to state', () => {
|
||||
mutations[types.SET_PORTALS_META](state, {
|
||||
count: 10,
|
||||
currentPage: 1,
|
||||
all_articles_count: 10,
|
||||
archived_articles_count: 10,
|
||||
draft_articles_count: 10,
|
||||
mine_articles_count: 10,
|
||||
});
|
||||
expect(state.meta).toEqual({
|
||||
count: 0,
|
||||
currentPage: 1,
|
||||
allArticlesCount: 10,
|
||||
archivedArticlesCount: 10,
|
||||
draftArticlesCount: 10,
|
||||
mineArticlesCount: 10,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user