feat: Portals store integration (#5185)
This commit is contained in:
@@ -1,9 +1,18 @@
|
||||
import ApiClient from '../ApiClient';
|
||||
/* global axios */
|
||||
|
||||
class ArticlesAPI extends ApiClient {
|
||||
import PortalsAPI from './portals';
|
||||
|
||||
class ArticlesAPI extends PortalsAPI {
|
||||
constructor() {
|
||||
super('articles', { accountScoped: true });
|
||||
}
|
||||
|
||||
getArticles({ pageNumber, portalSlug, locale, status, author_id }) {
|
||||
let baseUrl = `${this.url}/${portalSlug}/articles?page=${pageNumber}&locale=${locale}`;
|
||||
if (status !== undefined) baseUrl += `&status=${status}`;
|
||||
if (author_id) baseUrl += `&author_id=${author_id}`;
|
||||
return axios.get(baseUrl);
|
||||
}
|
||||
}
|
||||
|
||||
export default new ArticlesAPI();
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
/* global axios */
|
||||
import ApiClient from '../ApiClient';
|
||||
|
||||
class PortalsAPI extends ApiClient {
|
||||
constructor() {
|
||||
super('portals', { accountScoped: true });
|
||||
}
|
||||
|
||||
getArticles({ pageNumber, portalSlug, locale }) {
|
||||
return axios.get(
|
||||
`${this.url}/${portalSlug}/articles?page=${pageNumber}&locale=${locale}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PortalsAPI;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import articlesAPI from '../helpCenter/articles';
|
||||
import ApiClient from 'dashboard/api/helpCenter/portals';
|
||||
import describeWithAPIMock from './apiSpecHelper';
|
||||
|
||||
describe('#PortalAPI', () => {
|
||||
it('creates correct instance', () => {
|
||||
expect(articlesAPI).toBeInstanceOf(ApiClient);
|
||||
expect(articlesAPI).toHaveProperty('get');
|
||||
expect(articlesAPI).toHaveProperty('show');
|
||||
expect(articlesAPI).toHaveProperty('create');
|
||||
expect(articlesAPI).toHaveProperty('update');
|
||||
expect(articlesAPI).toHaveProperty('delete');
|
||||
expect(articlesAPI).toHaveProperty('getArticles');
|
||||
});
|
||||
describeWithAPIMock('API calls', context => {
|
||||
it('#getArticles', () => {
|
||||
articlesAPI.getArticles({
|
||||
pageNumber: 1,
|
||||
portalSlug: 'room-rental',
|
||||
locale: 'en-US',
|
||||
status: 'published',
|
||||
author_id: '1',
|
||||
});
|
||||
expect(context.axiosMock.get).toHaveBeenCalledWith(
|
||||
'/api/v1/portals/room-rental/articles?page=1&locale=en-US&status=published&author_id=1'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
import PortalsAPI from '../helpCenter/portals';
|
||||
import ApiClient from '../ApiClient';
|
||||
const portalAPI = new PortalsAPI();
|
||||
describe('#PortalAPI', () => {
|
||||
it('creates correct instance', () => {
|
||||
expect(portalAPI).toBeInstanceOf(ApiClient);
|
||||
expect(portalAPI).toHaveProperty('get');
|
||||
expect(portalAPI).toHaveProperty('show');
|
||||
expect(portalAPI).toHaveProperty('create');
|
||||
expect(portalAPI).toHaveProperty('update');
|
||||
expect(portalAPI).toHaveProperty('delete');
|
||||
});
|
||||
});
|
||||
@@ -31,7 +31,9 @@
|
||||
"NEW_BUTTON": "New Portal",
|
||||
"ACTIVE_BADGE": "active",
|
||||
"CHOOSE_LOCALE_LABEL": "Choose a locale",
|
||||
"LOADING_MESSAGE": "Loading portals...",
|
||||
"ARTICLES_LABEL": "articles",
|
||||
"NO_PORTALS_MESSAGE": "There are no available portals",
|
||||
"ADD_NEW_LOCALE": "Add a new locale",
|
||||
"POPOVER": {
|
||||
"TITLE": "Portals",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ category }}</td>
|
||||
<td>{{ category.name }}</td>
|
||||
<td>{{ readCount }}</td>
|
||||
<td>
|
||||
<Label :title="status" :color-scheme="labelColor" />
|
||||
@@ -48,8 +48,8 @@ export default {
|
||||
default: () => {},
|
||||
},
|
||||
category: {
|
||||
type: String,
|
||||
default: '',
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
readCount: {
|
||||
type: Number,
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
<table-footer
|
||||
v-if="articles.length"
|
||||
:on-page-change="onPageChange"
|
||||
:current-page="Number(currentPage)"
|
||||
:total-count="totalCount"
|
||||
|
||||
+43
-192
@@ -6,10 +6,10 @@
|
||||
@open-key-shortcut-modal="toggleKeyShortcutModal"
|
||||
@close-key-shortcut-modal="closeKeyShortcutModal"
|
||||
/>
|
||||
<div class="margin-right-small">
|
||||
<div v-if="portals.length" class="margin-right-small">
|
||||
<help-center-sidebar
|
||||
header-title="Help Center"
|
||||
sub-title="English"
|
||||
:header-title="headerTitle"
|
||||
:sub-title="localeName(selectedPortalLocale)"
|
||||
:accessible-menu-items="accessibleMenuItems"
|
||||
:additional-secondary-menu-items="additionalSecondaryMenuItems"
|
||||
@open-popover="openPortalPopover"
|
||||
@@ -30,8 +30,8 @@
|
||||
<portal-popover
|
||||
v-if="showPortalPopover"
|
||||
:portals="portals"
|
||||
:active-portal="selectedPortal"
|
||||
@close-popover="closePortalPopover"
|
||||
@open-portal-page="openPortalPage"
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
@@ -41,12 +41,12 @@ import { mapGetters } from 'vuex';
|
||||
|
||||
import { frontendURL } from '../../../../helper/URLHelper';
|
||||
import Sidebar from 'dashboard/components/layout/Sidebar';
|
||||
import PortalPopover from 'dashboard/routes/dashboard/helpcenter/components/PortalPopover';
|
||||
import HelpCenterSidebar from 'dashboard/routes/dashboard/helpcenter/components/Sidebar/Sidebar';
|
||||
import PortalPopover from '../components/PortalPopover.vue';
|
||||
import HelpCenterSidebar from '../components/Sidebar/Sidebar.vue';
|
||||
import CommandBar from 'dashboard/routes/dashboard/commands/commandbar.vue';
|
||||
import WootKeyShortcutModal from 'dashboard/components/widgets/modal/WootKeyShortcutModal';
|
||||
import NotificationPanel from 'dashboard/routes/dashboard/notifications/components/NotificationPanel.vue';
|
||||
|
||||
import portalMixin from '../mixins/portalMixin';
|
||||
export default {
|
||||
components: {
|
||||
Sidebar,
|
||||
@@ -56,6 +56,7 @@ export default {
|
||||
NotificationPanel,
|
||||
PortalPopover,
|
||||
},
|
||||
mixins: [portalMixin],
|
||||
data() {
|
||||
return {
|
||||
showShortcutModal: false,
|
||||
@@ -63,36 +64,49 @@ export default {
|
||||
showPortalPopover: false,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters({
|
||||
accountId: 'getCurrentAccountId',
|
||||
selectedPortal: 'portals/getSelectedPortal',
|
||||
portals: 'portals/allPortals',
|
||||
meta: 'portals/getMeta',
|
||||
isFetching: 'portals/isFetchingPortals',
|
||||
}),
|
||||
portalSlug() {
|
||||
return this.$route.params.portalSlug;
|
||||
selectedPortalSlug() {
|
||||
return this.portalSlug || this.selectedPortal?.slug;
|
||||
},
|
||||
locale() {
|
||||
return this.$route.params.locale;
|
||||
selectedPortalLocale() {
|
||||
return this.locale || this.selectedPortal?.meta?.default_locale;
|
||||
},
|
||||
accessibleMenuItems() {
|
||||
const {
|
||||
meta: {
|
||||
all_articles_count: allArticlesCount,
|
||||
mine_articles_count: mineArticlesCount,
|
||||
draft_articles_count: draftArticlesCount,
|
||||
archived_articles_count: archivedArticlesCount,
|
||||
} = {},
|
||||
} = this.selectedPortal;
|
||||
return [
|
||||
{
|
||||
icon: 'book',
|
||||
label: 'HELP_CENTER.ALL_ARTICLES',
|
||||
key: 'list_all_locale_articles',
|
||||
count: 199,
|
||||
count: allArticlesCount,
|
||||
toState: frontendURL(
|
||||
`accounts/${this.accountId}/portals/${this.portalSlug}/${this.locale}/articles`
|
||||
`accounts/${this.accountId}/portals/${this.selectedPortalSlug}/${this.selectedPortalLocale}/articles`
|
||||
),
|
||||
toolTip: 'All Articles',
|
||||
toStateName: 'list_all_locale_articles',
|
||||
toStateName: 'list_all_selectedPortalLocale_articles',
|
||||
},
|
||||
{
|
||||
icon: 'pen',
|
||||
label: 'HELP_CENTER.MY_ARTICLES',
|
||||
key: 'mine_articles',
|
||||
count: 112,
|
||||
count: mineArticlesCount,
|
||||
toState: frontendURL(
|
||||
`accounts/${this.accountId}/portals/${this.portalSlug}/${this.locale}/articles/mine`
|
||||
`accounts/${this.accountId}/portals/${this.selectedPortalSlug}/${this.selectedPortalLocale}/articles/mine`
|
||||
),
|
||||
toolTip: 'My articles',
|
||||
toStateName: 'mine_articles',
|
||||
@@ -101,9 +115,9 @@ export default {
|
||||
icon: 'draft',
|
||||
label: 'HELP_CENTER.DRAFT',
|
||||
key: 'list_draft_articles',
|
||||
count: 32,
|
||||
count: draftArticlesCount,
|
||||
toState: frontendURL(
|
||||
`accounts/${this.accountId}/portals/${this.portalSlug}/${this.locale}/articles/draft`
|
||||
`accounts/${this.accountId}/portals/${this.selectedPortalSlug}/${this.selectedPortalLocale}/articles/draft`
|
||||
),
|
||||
toolTip: 'Draft',
|
||||
toStateName: 'list_draft_articles',
|
||||
@@ -112,9 +126,9 @@ export default {
|
||||
icon: 'archive',
|
||||
label: 'HELP_CENTER.ARCHIVED',
|
||||
key: 'list_archived_articles',
|
||||
count: 10,
|
||||
count: archivedArticlesCount,
|
||||
toState: frontendURL(
|
||||
`accounts/${this.accountId}/portals/${this.portalSlug}/${this.locale}/articles/archived`
|
||||
`accounts/${this.accountId}/portals/${this.selectedPortalSlug}/${this.selectedPortalLocale}/articles/archived`
|
||||
),
|
||||
toolTip: 'Archived',
|
||||
toStateName: 'list_archived_articles',
|
||||
@@ -147,172 +161,6 @@ export default {
|
||||
`accounts/${this.accountId}/portals/:portalSlug/:locale/categories/channel`
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
label: 'Feature',
|
||||
count: 24,
|
||||
truncateLabel: true,
|
||||
toState: frontendURL(
|
||||
`accounts/${this.accountId}/portals/:portalSlug/:locale/categories/feature`
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
label: 'Advanced',
|
||||
count: 8,
|
||||
truncateLabel: true,
|
||||
toState: frontendURL(
|
||||
`accounts/${this.accountId}/portals/:portalSlug/:locale/categories/advanced`
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
label: 'Mobile app',
|
||||
count: 3,
|
||||
truncateLabel: true,
|
||||
toState: frontendURL(
|
||||
`accounts/${this.accountId}/portals/:portalSlug/:locale/categories/mobile-app`
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
label: 'Others',
|
||||
count: 39,
|
||||
truncateLabel: true,
|
||||
toState: frontendURL(
|
||||
`accounts/${this.accountId}/portals/:portalSlug/:locale/categories/others`
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
},
|
||||
portals() {
|
||||
return [
|
||||
{
|
||||
name: 'Chatwoot Help Center',
|
||||
id: 1,
|
||||
color: null,
|
||||
custom_domain: 'doc',
|
||||
articles_count: 123,
|
||||
header_text: null,
|
||||
homepage_link: null,
|
||||
page_title: null,
|
||||
slug: 'first_portal',
|
||||
archived: false,
|
||||
config: {
|
||||
allowed_locales: [
|
||||
{
|
||||
code: 'en',
|
||||
name: 'English',
|
||||
articles_count: 123,
|
||||
},
|
||||
{
|
||||
code: 'fr',
|
||||
name: 'Français',
|
||||
articles_count: 123,
|
||||
},
|
||||
{
|
||||
code: 'de',
|
||||
name: 'Deutsch',
|
||||
articles_count: 32,
|
||||
},
|
||||
{
|
||||
code: 'es',
|
||||
name: 'Español',
|
||||
articles_count: 12,
|
||||
},
|
||||
{
|
||||
code: 'it',
|
||||
name: 'Italiano',
|
||||
articles_count: 8,
|
||||
},
|
||||
],
|
||||
},
|
||||
locales: [
|
||||
{
|
||||
name: 'English',
|
||||
code: 'en',
|
||||
articles_count: 12,
|
||||
},
|
||||
{
|
||||
name: 'Español',
|
||||
code: 'es',
|
||||
articles_count: 42,
|
||||
},
|
||||
{
|
||||
name: 'French',
|
||||
code: 'fr',
|
||||
articles_count: 29,
|
||||
},
|
||||
{
|
||||
name: 'Italian',
|
||||
code: 'it',
|
||||
articles_count: 4,
|
||||
},
|
||||
{
|
||||
name: 'German',
|
||||
code: 'de',
|
||||
articles_count: 66,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Chatwoot Docs',
|
||||
id: 2,
|
||||
color: null,
|
||||
custom_domain: 'doc',
|
||||
articles_count: 124,
|
||||
header_text: null,
|
||||
homepage_link: null,
|
||||
page_title: null,
|
||||
slug: 'second_portal',
|
||||
archived: false,
|
||||
config: {
|
||||
allowed_locales: [
|
||||
{
|
||||
code: 'en',
|
||||
name: 'English',
|
||||
articles_count: 123,
|
||||
},
|
||||
{
|
||||
code: 'fr',
|
||||
name: 'Français',
|
||||
articles_count: 123,
|
||||
},
|
||||
{
|
||||
code: 'de',
|
||||
name: 'Deutsch',
|
||||
articles_count: 32,
|
||||
},
|
||||
{
|
||||
code: 'es',
|
||||
name: 'Español',
|
||||
articles_count: 12,
|
||||
},
|
||||
{
|
||||
code: 'it',
|
||||
name: 'Italiano',
|
||||
articles_count: 8,
|
||||
},
|
||||
],
|
||||
},
|
||||
locales: [
|
||||
{
|
||||
name: 'English',
|
||||
code: 'en',
|
||||
articles_count: 12,
|
||||
},
|
||||
{
|
||||
name: 'Japanese',
|
||||
code: 'jp',
|
||||
articles_count: 4,
|
||||
},
|
||||
{
|
||||
name: 'Mandarin',
|
||||
code: 'CH',
|
||||
articles_count: 6,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -320,8 +168,17 @@ export default {
|
||||
currentRoute() {
|
||||
return ' ';
|
||||
},
|
||||
headerTitle() {
|
||||
return this.selectedPortal.name;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.fetchPortals();
|
||||
},
|
||||
methods: {
|
||||
fetchPortals() {
|
||||
this.$store.dispatch('portals/index');
|
||||
},
|
||||
toggleKeyShortcutModal() {
|
||||
this.showShortcutModal = true;
|
||||
},
|
||||
@@ -340,12 +197,6 @@ export default {
|
||||
closePortalPopover() {
|
||||
this.showPortalPopover = false;
|
||||
},
|
||||
openPortalPage() {
|
||||
this.$router.push({
|
||||
name: 'list_all_portals',
|
||||
});
|
||||
this.showPortalPopover = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
+11
-17
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-for="portal in portals" :key="portal.id" class="portal">
|
||||
<div class="portal">
|
||||
<thumbnail :username="portal.name" variant="square" />
|
||||
<div class="container">
|
||||
<header>
|
||||
@@ -118,7 +118,6 @@
|
||||
class="theme-color"
|
||||
:style="{ background: portal.color }"
|
||||
/>
|
||||
<span class="text-block-title">{{ portal.page_title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="configuration-item">
|
||||
@@ -127,7 +126,7 @@
|
||||
'HELP_CENTER.PORTAL.PORTAL_SETTINGS.LIST_ITEM.PORTAL_CONFIG.ITEMS.SUB_TEXT'
|
||||
)
|
||||
}}</label>
|
||||
<span class="text-block-title">{{ portal.page_title }}</span>
|
||||
<span class="text-block-title">{{ portal.header_text }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -141,8 +140,8 @@
|
||||
}}
|
||||
</h2>
|
||||
<locale-item-table
|
||||
:portals="portal"
|
||||
:selected-locale-code="selectedLocaleCode"
|
||||
:locales="locales"
|
||||
:selected-locale-code="portal.meta.default_locale"
|
||||
@swap="swapLocale"
|
||||
@delete="deleteLocale"
|
||||
/>
|
||||
@@ -163,33 +162,28 @@ export default {
|
||||
LocaleItemTable,
|
||||
},
|
||||
props: {
|
||||
portals: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
portal: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
status: {
|
||||
type: String,
|
||||
default: '',
|
||||
values: ['archived', 'draft', 'published'],
|
||||
},
|
||||
selectedLocaleCode: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
labelColor() {
|
||||
switch (this.status) {
|
||||
case 'archived':
|
||||
return 'secondary';
|
||||
case 'draft':
|
||||
case 'Archived':
|
||||
return 'warning';
|
||||
default:
|
||||
return 'success';
|
||||
}
|
||||
},
|
||||
defaultLocale(code) {
|
||||
return code === this.selectedLocaleCode;
|
||||
|
||||
locales() {
|
||||
return this.portal ? this.portal.config.allowed_locales : [];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
||||
+8
-5
@@ -37,9 +37,9 @@
|
||||
<td colspan="100%" class="horizontal-line" />
|
||||
</tr>
|
||||
<tbody>
|
||||
<tr v-for="locale in portals.locales" :key="locale.code">
|
||||
<tr v-for="locale in locales" :key="locale.code">
|
||||
<td>
|
||||
<span>{{ locale.name }}</span>
|
||||
<span>{{ localeName(locale.code) }}</span>
|
||||
<Label
|
||||
v-if="locale.code === selectedLocaleCode"
|
||||
:title="
|
||||
@@ -95,20 +95,23 @@
|
||||
|
||||
<script>
|
||||
import Label from 'dashboard/components/ui/Label';
|
||||
import portalMixin from '../mixins/portalMixin';
|
||||
export default {
|
||||
components: {
|
||||
Label,
|
||||
},
|
||||
mixins: [portalMixin],
|
||||
props: {
|
||||
portals: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
locales: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
selectedLocaleCode: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
swapLocale() {
|
||||
this.$emit('swap');
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
color-scheme="secondary"
|
||||
icon="settings"
|
||||
size="small"
|
||||
@click="openPortalPage"
|
||||
>
|
||||
{{ $t('HELP_CENTER.PORTAL.POPOVER.PORTAL_SETTINGS') }}
|
||||
</woot-button>
|
||||
@@ -24,6 +23,8 @@
|
||||
v-for="portal in portals"
|
||||
:key="portal.id"
|
||||
:portal="portal"
|
||||
:active="portal.id === activePortal.id"
|
||||
@open-portal-page="openPortalPage"
|
||||
/>
|
||||
</div>
|
||||
<footer>
|
||||
@@ -50,13 +51,26 @@ export default {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
activePortal: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
closePortalPopover() {
|
||||
this.$emit('close-popover');
|
||||
},
|
||||
openPortalPage() {
|
||||
this.$emit('open-portal-page');
|
||||
openPortalPage({ slug, locale }) {
|
||||
this.$emit('close-popover');
|
||||
const portal = this.portals.find(p => p.slug === slug);
|
||||
this.$store.dispatch('portals/setPortalId', portal.id);
|
||||
this.$router.push({
|
||||
name: 'list_all_locale_articles',
|
||||
params: {
|
||||
portalSlug: slug,
|
||||
locale: locale,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div>
|
||||
<h2 class="portal-title">{{ portal.name }}</h2>
|
||||
<p class="portal-count">
|
||||
{{ portal.articles_count }}
|
||||
{{ articlesCount }}
|
||||
{{ $t('HELP_CENTER.PORTAL.ARTICLES_LABEL') }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -19,7 +19,7 @@
|
||||
{{ $t('HELP_CENTER.PORTAL.CHOOSE_LOCALE_LABEL') }}
|
||||
</h2>
|
||||
<ul>
|
||||
<li v-for="locale in portal.locales" :key="locale.code">
|
||||
<li v-for="locale in locales" :key="locale.code">
|
||||
<label :for="`locale-${locale.code}`" class="locale-item">
|
||||
<input
|
||||
:id="`locale-${locale.code}`"
|
||||
@@ -27,9 +27,10 @@
|
||||
type="radio"
|
||||
name="locale"
|
||||
:value="locale.code"
|
||||
@click="onClick(locale.code, portal)"
|
||||
/>
|
||||
<div>
|
||||
<p>{{ locale.name }}</p>
|
||||
<p>{{ localeName(locale.code) }}</p>
|
||||
<span>
|
||||
{{ locale.articles_count }}
|
||||
{{ $t('HELP_CENTER.PORTAL.ARTICLES_LABEL') }} -
|
||||
@@ -49,10 +50,12 @@
|
||||
|
||||
<script>
|
||||
import thumbnail from 'dashboard/components/widgets/Thumbnail';
|
||||
import portalMixin from '../mixins/portalMixin';
|
||||
export default {
|
||||
components: {
|
||||
thumbnail,
|
||||
},
|
||||
mixins: [portalMixin],
|
||||
props: {
|
||||
portal: {
|
||||
type: Object,
|
||||
@@ -65,11 +68,24 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedLocale: '',
|
||||
selectedLocale: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
locales() {
|
||||
return this.portal?.config?.allowed_locales;
|
||||
},
|
||||
articlesCount() {
|
||||
return this.portal?.meta?.all_articles_count;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.selectedLocale = this.portal.locales[0].code;
|
||||
this.selectedLocale = this.locale || this.portal?.meta?.default_locale;
|
||||
},
|
||||
methods: {
|
||||
onClick(code, portal) {
|
||||
this.$emit('open-portal-page', { slug: portal.slug, locale: code });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { mapGetters } from 'vuex';
|
||||
import { frontendURL } from 'dashboard/helper/URLHelper';
|
||||
import allLocales from 'shared/constants/locales.js';
|
||||
export default {
|
||||
computed: {
|
||||
...mapGetters({ accountId: 'getCurrentAccountId' }),
|
||||
@@ -16,5 +17,8 @@ export default {
|
||||
`accounts/${this.accountId}/portals/${this.portalSlug}/${this.locale}/articles/${id}`
|
||||
);
|
||||
},
|
||||
localeName(code) {
|
||||
return allLocales[code];
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
+9
-1
@@ -40,7 +40,7 @@ describe('portalMixin', () => {
|
||||
expect(wrapper.vm.accountId).toBe(1);
|
||||
});
|
||||
|
||||
it('returns portal url', () => {
|
||||
it('returns article url', () => {
|
||||
router.push({
|
||||
name: 'list_all_locale_articles',
|
||||
params: { portalSlug: 'fur-rent', locale: 'en' },
|
||||
@@ -65,4 +65,12 @@ describe('portalMixin', () => {
|
||||
});
|
||||
expect(wrapper.vm.portalSlug).toBe('campaign');
|
||||
});
|
||||
|
||||
it('returns locale name', () => {
|
||||
router.push({
|
||||
name: 'list_all_locale_articles',
|
||||
params: { portalSlug: 'fur-rent', locale: 'es' },
|
||||
});
|
||||
expect(wrapper.vm.localeName('es')).toBe('Spanish');
|
||||
});
|
||||
});
|
||||
|
||||
+38
-8
@@ -13,12 +13,12 @@
|
||||
:total-count="meta.count"
|
||||
@on-page-change="onPageChange"
|
||||
/>
|
||||
<div v-if="isFetching" class="articles--loader">
|
||||
<div v-if="shouldShowLoader" class="articles--loader">
|
||||
<spinner />
|
||||
<span>{{ $t('HELP_CENTER.TABLE.LOADING_MESSAGE') }}</span>
|
||||
</div>
|
||||
<empty-state
|
||||
v-else-if="!isFetching && !articles.length"
|
||||
v-else-if="shouldShowEmptyState"
|
||||
:title="$t('HELP_CENTER.TABLE.NO_ARTICLES')"
|
||||
/>
|
||||
</div>
|
||||
@@ -48,10 +48,13 @@ export default {
|
||||
uiFlags: 'articles/uiFlags',
|
||||
meta: 'articles/getMeta',
|
||||
isFetching: 'articles/isFetching',
|
||||
currentUserId: 'getCurrentUserID',
|
||||
}),
|
||||
|
||||
showEmptyState() {
|
||||
return this.articles.length === 0;
|
||||
shouldShowEmptyState() {
|
||||
return !this.isFetching && !this.articles.length;
|
||||
},
|
||||
shouldShowLoader() {
|
||||
return this.isFetching && !this.articles.length;
|
||||
},
|
||||
articleType() {
|
||||
return this.$route.path.split('/').pop();
|
||||
@@ -68,19 +71,46 @@ export default {
|
||||
return this.$t('HELP_CENTER.HEADER.TITLES.ALL_ARTICLES');
|
||||
}
|
||||
},
|
||||
status() {
|
||||
switch (this.articleType) {
|
||||
case 'draft':
|
||||
return 0;
|
||||
case 'published':
|
||||
return 1;
|
||||
case 'archived':
|
||||
return 2;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
author() {
|
||||
if (this.articleType === 'mine') {
|
||||
return this.currentUserId;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.pageNumber = 1;
|
||||
this.fetchArticles();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.fetchArticles({ pageNumber: this.pageNumber });
|
||||
this.fetchArticles();
|
||||
},
|
||||
|
||||
methods: {
|
||||
newArticlePage() {
|
||||
this.$router.push({ name: 'new_article' });
|
||||
},
|
||||
fetchArticles({ pageNumber }) {
|
||||
fetchArticles() {
|
||||
this.$store.dispatch('articles/index', {
|
||||
pageNumber,
|
||||
pageNumber: this.pageNumber,
|
||||
portalSlug: this.$route.params.portalSlug,
|
||||
locale: this.$route.params.locale,
|
||||
status: this.status,
|
||||
author_id: this.author,
|
||||
});
|
||||
},
|
||||
onPageChange(page) {
|
||||
|
||||
+37
-119
@@ -8,134 +8,46 @@
|
||||
</div>
|
||||
<div class="portal-container">
|
||||
<portal-list-item
|
||||
:portals="portals"
|
||||
status="published"
|
||||
selected-locale-code="en-US"
|
||||
v-for="portal in portals"
|
||||
:key="portal.id"
|
||||
:portal="portal"
|
||||
:status="portalStatus"
|
||||
/>
|
||||
<div v-if="isFetching" class="portals--loader">
|
||||
<spinner />
|
||||
<span>{{ $t('HELP_CENTER.PORTAL.LOADING_MESSAGE') }}</span>
|
||||
</div>
|
||||
<empty-state
|
||||
v-else-if="shouldShowEmptyState"
|
||||
:title="$t('HELP_CENTER.PORTAL.NO_PORTALS_MESSAGE')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PortalListItem from 'dashboard/routes/dashboard/helpcenter/components/PortalListItem';
|
||||
import { mapGetters } from 'vuex';
|
||||
import PortalListItem from '../../components/PortalListItem';
|
||||
import Spinner from 'shared/components/Spinner.vue';
|
||||
import EmptyState from 'dashboard/components/widgets/EmptyState';
|
||||
export default {
|
||||
components: {
|
||||
PortalListItem,
|
||||
EmptyState,
|
||||
Spinner,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// Dummy data for testing will remove once the state is implemented.
|
||||
portals: [
|
||||
{
|
||||
name: 'Chatwoot Help Center',
|
||||
id: 1,
|
||||
color: 'red',
|
||||
custom_domain: 'help-center.chatwoot.com',
|
||||
articles_count: 123,
|
||||
header_text: 'Help center',
|
||||
homepage_link: null,
|
||||
page_title: 'English',
|
||||
slug: 'help-center',
|
||||
archived: false,
|
||||
config: {
|
||||
allowed_locales: [
|
||||
{
|
||||
code: 'en-US',
|
||||
name: 'English',
|
||||
articles_count: 123,
|
||||
categories_count: 42,
|
||||
},
|
||||
{
|
||||
code: 'fr-FR',
|
||||
name: 'Français',
|
||||
articles_count: 23,
|
||||
categories_count: 11,
|
||||
},
|
||||
{
|
||||
code: 'de-DE',
|
||||
name: 'Deutsch',
|
||||
articles_count: 32,
|
||||
categories_count: 12,
|
||||
},
|
||||
{
|
||||
code: 'es-ES',
|
||||
name: 'Español',
|
||||
articles_count: 12,
|
||||
categories_count: 4,
|
||||
},
|
||||
],
|
||||
},
|
||||
locales: [
|
||||
{
|
||||
code: 'en-US',
|
||||
name: 'English',
|
||||
articles_count: 123,
|
||||
categories_count: 42,
|
||||
},
|
||||
{
|
||||
code: 'fr-FR',
|
||||
name: 'Français',
|
||||
articles_count: 23,
|
||||
categories_count: 11,
|
||||
},
|
||||
{
|
||||
code: 'de-DE',
|
||||
name: 'Deutsch',
|
||||
articles_count: 32,
|
||||
categories_count: 12,
|
||||
},
|
||||
{
|
||||
code: 'es-ES',
|
||||
name: 'Español',
|
||||
articles_count: 12,
|
||||
categories_count: 4,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Chatwoot Docs',
|
||||
id: 2,
|
||||
color: 'green',
|
||||
custom_domain: 'doc-chatwoot.com',
|
||||
articles_count: 67,
|
||||
header_text: 'Docs',
|
||||
homepage_link: null,
|
||||
page_title: 'Portal',
|
||||
slug: 'second_portal',
|
||||
archived: false,
|
||||
config: {
|
||||
allowed_locales: [
|
||||
{
|
||||
name: 'English',
|
||||
code: 'en-EN',
|
||||
articles_count: 12,
|
||||
categories_count: 66,
|
||||
},
|
||||
{
|
||||
name: 'Mandarin',
|
||||
code: 'ch-CH',
|
||||
articles_count: 6,
|
||||
categories_count: 23,
|
||||
},
|
||||
],
|
||||
},
|
||||
locales: [
|
||||
{
|
||||
name: 'English',
|
||||
code: 'en-EN',
|
||||
articles_count: 12,
|
||||
categories_count: 66,
|
||||
},
|
||||
{
|
||||
name: 'Mandarin',
|
||||
code: 'ch-CH',
|
||||
articles_count: 6,
|
||||
categories_count: 23,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
computed: {
|
||||
...mapGetters({
|
||||
portals: 'portals/allPortals',
|
||||
meta: 'portals/getMeta',
|
||||
isFetching: 'portals/isFetchingPortals',
|
||||
}),
|
||||
portalStatus() {
|
||||
return this.archived ? 'Archived' : 'Live';
|
||||
},
|
||||
shouldShowEmptyState() {
|
||||
return !this.isFetching && !this.portals.length;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
createPortal() {
|
||||
@@ -149,7 +61,13 @@ export default {
|
||||
.container {
|
||||
padding: var(--space-small) var(--space-normal);
|
||||
width: 100%;
|
||||
|
||||
.portals--loader {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
font-size: var(--font-size-default);
|
||||
justify-content: center;
|
||||
padding: var(--space-big);
|
||||
}
|
||||
.header-wrap {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -36,6 +36,8 @@ import teams from './modules/teams';
|
||||
import userNotificationSettings from './modules/userNotificationSettings';
|
||||
import webhooks from './modules/webhooks';
|
||||
import articles from './modules/helpCenterArticles';
|
||||
import portals from './modules/helpCenterPortals';
|
||||
import categories from './modules/helpCenterCategories';
|
||||
|
||||
Vue.use(Vuex);
|
||||
export default new Vuex.Store({
|
||||
@@ -75,5 +77,7 @@ export default new Vuex.Store({
|
||||
userNotificationSettings,
|
||||
webhooks,
|
||||
articles,
|
||||
portals,
|
||||
categories,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
import PortalAPI from 'dashboard/api/helpCenter/portals';
|
||||
import articlesAPI from 'dashboard/api/helpCenter/articles';
|
||||
import { throwErrorMessage } from 'dashboard/store/utils/api';
|
||||
const portalAPIs = new PortalAPI();
|
||||
|
||||
import types from '../../mutation-types';
|
||||
export const actions = {
|
||||
index: async ({ commit }, { pageNumber, portalSlug, locale }) => {
|
||||
index: async (
|
||||
{ commit },
|
||||
{ pageNumber, portalSlug, locale, status, author_id }
|
||||
) => {
|
||||
try {
|
||||
commit(types.SET_UI_FLAG, { isFetching: true });
|
||||
const {
|
||||
data: { payload, meta },
|
||||
} = await portalAPIs.getArticles({
|
||||
} = await articlesAPI.getArticles({
|
||||
pageNumber,
|
||||
portalSlug,
|
||||
locale,
|
||||
status,
|
||||
author_id,
|
||||
});
|
||||
const articleIds = payload.map(article => article.id);
|
||||
commit(types.CLEAR_ARTICLES);
|
||||
|
||||
@@ -8,7 +8,7 @@ export const defaultHelpCenterFlags = {
|
||||
isDeleting: false,
|
||||
};
|
||||
const state = {
|
||||
categoriess: {
|
||||
categories: {
|
||||
byId: {},
|
||||
byLocale: {},
|
||||
allIds: [],
|
||||
|
||||
@@ -3,13 +3,22 @@ import { throwErrorMessage } from 'dashboard/store/utils/api';
|
||||
import { types } from './mutations';
|
||||
const portalAPIs = new PortalAPI();
|
||||
export const actions = {
|
||||
index: async ({ commit }) => {
|
||||
index: async ({ commit, state, dispatch }) => {
|
||||
try {
|
||||
commit(types.SET_UI_FLAG, { isFetching: true });
|
||||
const { data } = await portalAPIs.get();
|
||||
const portalIds = data.map(portal => portal.id);
|
||||
commit(types.ADD_MANY_PORTALS_ENTRY, data);
|
||||
const {
|
||||
data: { payload, meta },
|
||||
} = await portalAPIs.get();
|
||||
commit(types.CLEAR_PORTALS);
|
||||
const portalIds = payload.map(portal => portal.id);
|
||||
commit(types.ADD_MANY_PORTALS_ENTRY, payload);
|
||||
commit(types.ADD_MANY_PORTALS_IDS, portalIds);
|
||||
const { selectedPortalId } = state;
|
||||
// Check if selected portal is still in the portals list
|
||||
if (!portalIds.includes(selectedPortalId)) {
|
||||
dispatch('setPortalId', portalIds[0]);
|
||||
}
|
||||
commit(types.SET_PORTALS_META, meta);
|
||||
} catch (error) {
|
||||
throwErrorMessage(error);
|
||||
} finally {
|
||||
@@ -68,4 +77,8 @@ export const actions = {
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
setPortalId: async ({ commit }, portalId) => {
|
||||
commit(types.SET_SELECTED_PORTAL_ID, portalId);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -16,11 +16,18 @@ export const getters = {
|
||||
},
|
||||
allPortals: (...getterArguments) => {
|
||||
const [state, _getters] = getterArguments;
|
||||
|
||||
const portals = state.portals.allIds.map(id => {
|
||||
return _getters.portalById(id);
|
||||
});
|
||||
return portals;
|
||||
},
|
||||
count: state => state.portals.allIds.length || 0,
|
||||
getMeta: state => {
|
||||
return state.meta;
|
||||
},
|
||||
getSelectedPortal: (...getterArguments) => {
|
||||
const [state, _getters] = getterArguments;
|
||||
const { selectedPortalId } = state.portals;
|
||||
return _getters.portalById(selectedPortalId);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -9,6 +9,11 @@ export const defaultPortalFlags = {
|
||||
};
|
||||
|
||||
const state = {
|
||||
meta: {
|
||||
count: 0,
|
||||
currentPage: 1,
|
||||
},
|
||||
|
||||
portals: {
|
||||
byId: {},
|
||||
allIds: [],
|
||||
@@ -20,6 +25,7 @@ const state = {
|
||||
meta: {
|
||||
byId: {},
|
||||
},
|
||||
selectedPortalId: null,
|
||||
},
|
||||
uiFlags: {
|
||||
allFetched: false,
|
||||
|
||||
@@ -4,9 +4,12 @@ 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',
|
||||
SET_SELECTED_PORTAL_ID: 'setSelectedPortalId',
|
||||
UPDATE_PORTAL_ENTRY: 'updatePortalEntry',
|
||||
REMOVE_PORTAL_ENTRY: 'removePortalEntry',
|
||||
REMOVE_PORTAL_ID: 'removePortalId',
|
||||
@@ -32,9 +35,23 @@ export const mutations = {
|
||||
portals.forEach(portal => {
|
||||
allPortals[portal.id] = portal;
|
||||
});
|
||||
Vue.set($state.portals, 'byId', {
|
||||
allPortals,
|
||||
});
|
||||
Vue.set($state.portals, 'byId', allPortals);
|
||||
},
|
||||
|
||||
[types.CLEAR_PORTALS]: $state => {
|
||||
Vue.set($state.portals, 'byId', {});
|
||||
Vue.set($state.portals, 'allIds', []);
|
||||
Vue.set($state.portals, 'uiFlags', {});
|
||||
},
|
||||
|
||||
[types.SET_PORTALS_META]: ($state, data) => {
|
||||
const { portals_count: count, current_page: currentPage } = data;
|
||||
Vue.set($state.meta, 'count', count);
|
||||
Vue.set($state.meta, 'currentPage', currentPage);
|
||||
},
|
||||
|
||||
[types.SET_SELECTED_PORTAL_ID]: ($state, portalId) => {
|
||||
Vue.set($state.portals, 'selectedPortalId', portalId);
|
||||
},
|
||||
|
||||
[types.ADD_PORTAL_ID]($state, portalId) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { types } from '../mutations';
|
||||
import { apiResponse } from './fixtures';
|
||||
|
||||
const commit = jest.fn();
|
||||
const dispatch = jest.fn();
|
||||
global.axios = axios;
|
||||
jest.mock('axios');
|
||||
|
||||
@@ -11,11 +12,20 @@ describe('#actions', () => {
|
||||
describe('#index', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.get.mockResolvedValue({ data: apiResponse });
|
||||
await actions.index({ commit });
|
||||
await actions.index({
|
||||
commit,
|
||||
dispatch,
|
||||
state: {
|
||||
selectedPortalId: 4,
|
||||
},
|
||||
});
|
||||
expect(dispatch.mock.calls).toMatchObject([['setPortalId', 1]]);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_UI_FLAG, { isFetching: true }],
|
||||
[types.ADD_MANY_PORTALS_ENTRY, apiResponse],
|
||||
[types.CLEAR_PORTALS],
|
||||
[types.ADD_MANY_PORTALS_ENTRY, apiResponse.payload],
|
||||
[types.ADD_MANY_PORTALS_IDS, [1, 2]],
|
||||
[types.SET_PORTALS_META, { current_page: 1, portals_count: 1 }],
|
||||
[types.SET_UI_FLAG, { isFetching: false }],
|
||||
]);
|
||||
});
|
||||
@@ -31,7 +41,7 @@ describe('#actions', () => {
|
||||
|
||||
describe('#create', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.post.mockResolvedValue({ data: apiResponse[1] });
|
||||
axios.post.mockResolvedValue({ data: apiResponse.payload[1] });
|
||||
await actions.create(
|
||||
{ commit },
|
||||
{
|
||||
@@ -42,7 +52,7 @@ describe('#actions', () => {
|
||||
);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_UI_FLAG, { isCreating: true }],
|
||||
[types.ADD_PORTAL_ENTRY, apiResponse[1]],
|
||||
[types.ADD_PORTAL_ENTRY, apiResponse.payload[1]],
|
||||
[types.ADD_PORTAL_ID, 2],
|
||||
[types.SET_UI_FLAG, { isCreating: false }],
|
||||
]);
|
||||
@@ -59,14 +69,14 @@ describe('#actions', () => {
|
||||
|
||||
describe('#update', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.patch.mockResolvedValue({ data: apiResponse[1] });
|
||||
await actions.update({ commit }, apiResponse[1]);
|
||||
axios.patch.mockResolvedValue({ data: apiResponse.payload[1] });
|
||||
await actions.update({ commit }, apiResponse.payload[1]);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[
|
||||
types.SET_HELP_PORTAL_UI_FLAG,
|
||||
{ uiFlags: { isUpdating: true }, portalId: 2 },
|
||||
],
|
||||
[types.UPDATE_PORTAL_ENTRY, apiResponse[1]],
|
||||
[types.UPDATE_PORTAL_ENTRY, apiResponse.payload[1]],
|
||||
[
|
||||
types.SET_HELP_PORTAL_UI_FLAG,
|
||||
{ uiFlags: { isUpdating: false }, portalId: 2 },
|
||||
@@ -75,9 +85,9 @@ describe('#actions', () => {
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.patch.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await expect(actions.update({ commit }, apiResponse[1])).rejects.toThrow(
|
||||
Error
|
||||
);
|
||||
await expect(
|
||||
actions.update({ commit }, apiResponse.payload[1])
|
||||
).rejects.toThrow(Error);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[
|
||||
types.SET_HELP_PORTAL_UI_FLAG,
|
||||
@@ -123,4 +133,11 @@ describe('#actions', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
describe('#setPortalId', () => {
|
||||
it('sends correct actions', async () => {
|
||||
axios.delete.mockResolvedValue({});
|
||||
await actions.setPortalId({ commit }, 1);
|
||||
expect(commit.mock.calls).toEqual([[types.SET_SELECTED_PORTAL_ID, 1]]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
export default {
|
||||
meta: {
|
||||
count: 0,
|
||||
currentPage: 1,
|
||||
},
|
||||
portals: {
|
||||
byId: {
|
||||
1: {
|
||||
@@ -36,6 +40,7 @@ export default {
|
||||
1: { isFetching: false, isUpdating: true, isDeleting: false },
|
||||
},
|
||||
},
|
||||
selectedPortalId: 1,
|
||||
},
|
||||
uiFlags: {
|
||||
allFetched: false,
|
||||
@@ -43,33 +48,39 @@ export default {
|
||||
},
|
||||
};
|
||||
|
||||
export const apiResponse = [
|
||||
{
|
||||
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'],
|
||||
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'],
|
||||
{
|
||||
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,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
@@ -42,4 +42,9 @@ describe('#getters', () => {
|
||||
const state = portal;
|
||||
expect(getters.count(state)).toEqual(2);
|
||||
});
|
||||
|
||||
it('getMeta', () => {
|
||||
const state = portal;
|
||||
expect(getters.getMeta(state)).toEqual({ count: 0, currentPage: 1 });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -92,4 +92,33 @@ describe('#mutations', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#SET_PORTALS_META', () => {
|
||||
it('add meta to state', () => {
|
||||
mutations[types.SET_PORTALS_META](state, {
|
||||
portals_count: 10,
|
||||
current_page: 1,
|
||||
});
|
||||
expect(state.meta).toEqual({
|
||||
count: 10,
|
||||
currentPage: 1,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#SET_SELECTED_PORTAL_ID', () => {
|
||||
it('set selected portal id', () => {
|
||||
mutations[types.SET_SELECTED_PORTAL_ID](state, 4);
|
||||
expect(state.portals.selectedPortalId).toEqual(4);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user