mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-02 12:08:01 +00:00
191 lines
5.5 KiB
Vue
191 lines
5.5 KiB
Vue
<script setup>
|
|
import { computed } from 'vue';
|
|
import { useRouter, useRoute } from 'vue-router';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useMapGetter } from 'dashboard/composables/store.js';
|
|
import { ARTICLE_TABS, CATEGORY_ALL } from 'dashboard/helper/portalHelper';
|
|
|
|
import HelpCenterLayout from 'dashboard/components-next/HelpCenter/HelpCenterLayout.vue';
|
|
import ArticleList from 'dashboard/components-next/HelpCenter/Pages/ArticlePage/ArticleList.vue';
|
|
import ArticleHeaderControls from 'dashboard/components-next/HelpCenter/Pages/ArticlePage/ArticleHeaderControls.vue';
|
|
import CategoryHeaderControls from 'dashboard/components-next/HelpCenter/Pages/CategoryPage/CategoryHeaderControls.vue';
|
|
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
|
|
import ArticleEmptyState from 'dashboard/components-next/HelpCenter/EmptyState/Article/ArticleEmptyState.vue';
|
|
|
|
const props = defineProps({
|
|
articles: {
|
|
type: Array,
|
|
required: true,
|
|
},
|
|
categories: {
|
|
type: Array,
|
|
required: true,
|
|
},
|
|
allowedLocales: {
|
|
type: Array,
|
|
required: true,
|
|
},
|
|
portalName: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
meta: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
isCategoryArticles: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
});
|
|
|
|
const emit = defineEmits(['pageChange', 'fetchPortal']);
|
|
|
|
const router = useRouter();
|
|
const route = useRoute();
|
|
const { t } = useI18n();
|
|
|
|
const isSwitchingPortal = useMapGetter('portals/isSwitchingPortal');
|
|
const isFetching = useMapGetter('articles/isFetching');
|
|
|
|
const hasNoArticles = computed(
|
|
() => !isFetching.value && !props.articles.length
|
|
);
|
|
|
|
const isLoading = computed(() => isFetching.value || isSwitchingPortal.value);
|
|
|
|
const totalArticlesCount = computed(() => props.meta.allArticlesCount);
|
|
|
|
const hasNoArticlesInPortal = computed(
|
|
() => totalArticlesCount.value === 0 && !props.isCategoryArticles
|
|
);
|
|
|
|
const shouldShowPaginationFooter = computed(() => {
|
|
return !(isFetching.value || isSwitchingPortal.value || hasNoArticles.value);
|
|
});
|
|
|
|
const updateRoute = newParams => {
|
|
const { portalSlug, locale, tab, categorySlug } = route.params;
|
|
router.push({
|
|
name: 'portals_articles_index',
|
|
params: {
|
|
portalSlug,
|
|
locale: newParams.locale ?? locale,
|
|
tab: newParams.tab ?? tab,
|
|
categorySlug: newParams.categorySlug ?? categorySlug,
|
|
...newParams,
|
|
},
|
|
});
|
|
};
|
|
|
|
const articlesCount = computed(() => {
|
|
const { tab } = route.params;
|
|
const { meta } = props;
|
|
const countMap = {
|
|
'': meta.articlesCount,
|
|
mine: meta.mineArticlesCount,
|
|
draft: meta.draftArticlesCount,
|
|
archived: meta.archivedArticlesCount,
|
|
};
|
|
return Number(countMap[tab] || countMap['']);
|
|
});
|
|
|
|
const showArticleHeaderControls = computed(
|
|
() =>
|
|
!hasNoArticlesInPortal.value &&
|
|
!props.isCategoryArticles &&
|
|
!isSwitchingPortal.value
|
|
);
|
|
|
|
const showCategoryHeaderControls = computed(
|
|
() => props.isCategoryArticles && !isSwitchingPortal.value
|
|
);
|
|
|
|
const getEmptyStateText = type => {
|
|
if (props.isCategoryArticles) {
|
|
return t(`HELP_CENTER.ARTICLES_PAGE.EMPTY_STATE.CATEGORY.${type}`);
|
|
}
|
|
const tabName = route.params.tab?.toUpperCase() || 'ALL';
|
|
return t(`HELP_CENTER.ARTICLES_PAGE.EMPTY_STATE.${tabName}.${type}`);
|
|
};
|
|
|
|
const getEmptyStateTitle = computed(() => getEmptyStateText('TITLE'));
|
|
const getEmptyStateSubtitle = computed(() => getEmptyStateText('SUBTITLE'));
|
|
|
|
const handleTabChange = tab =>
|
|
updateRoute({ tab: tab.value === ARTICLE_TABS.ALL ? '' : tab.value });
|
|
|
|
const handleCategoryAction = value =>
|
|
updateRoute({ categorySlug: value === CATEGORY_ALL ? '' : value });
|
|
|
|
const handleLocaleAction = value => {
|
|
updateRoute({ locale: value, categorySlug: '' });
|
|
emit('fetchPortal', value);
|
|
};
|
|
const handlePageChange = page => emit('pageChange', page);
|
|
|
|
const navigateToNewArticlePage = () => {
|
|
const { categorySlug, locale } = route.params;
|
|
router.push({
|
|
name: 'portals_articles_new',
|
|
params: { categorySlug, locale },
|
|
});
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<HelpCenterLayout
|
|
:current-page="Number(meta.currentPage)"
|
|
:total-items="articlesCount"
|
|
:items-per-page="25"
|
|
:header="portalName"
|
|
:show-pagination-footer="shouldShowPaginationFooter"
|
|
@update:current-page="handlePageChange"
|
|
>
|
|
<template #header-actions>
|
|
<div class="flex items-end justify-between">
|
|
<ArticleHeaderControls
|
|
v-if="showArticleHeaderControls"
|
|
:categories="categories"
|
|
:allowed-locales="allowedLocales"
|
|
:meta="meta"
|
|
@tab-change="handleTabChange"
|
|
@locale-change="handleLocaleAction"
|
|
@category-change="handleCategoryAction"
|
|
@new-article="navigateToNewArticlePage"
|
|
/>
|
|
<CategoryHeaderControls
|
|
v-else-if="showCategoryHeaderControls"
|
|
:categories="categories"
|
|
:allowed-locales="allowedLocales"
|
|
:has-selected-category="isCategoryArticles"
|
|
/>
|
|
</div>
|
|
</template>
|
|
<template #content>
|
|
<div
|
|
v-if="isLoading"
|
|
class="flex items-center justify-center py-10 text-n-slate-11"
|
|
>
|
|
<Spinner />
|
|
</div>
|
|
<ArticleList
|
|
v-else-if="!hasNoArticles"
|
|
:articles="articles"
|
|
:is-category-articles="isCategoryArticles"
|
|
/>
|
|
<ArticleEmptyState
|
|
v-else
|
|
class="pt-14"
|
|
:title="getEmptyStateTitle"
|
|
:subtitle="getEmptyStateSubtitle"
|
|
:show-button="hasNoArticlesInPortal"
|
|
:button-label="
|
|
t('HELP_CENTER.ARTICLES_PAGE.EMPTY_STATE.ALL.BUTTON_LABEL')
|
|
"
|
|
@click="navigateToNewArticlePage"
|
|
/>
|
|
</template>
|
|
</HelpCenterLayout>
|
|
</template>
|