iachat/app/javascript/dashboard/routes/dashboard/helpcenter/components/ArticleTable.vue
2023-11-23 02:58:00 +05:30

162 lines
4.6 KiB
Vue

<template>
<div class="w-full">
<div
class="my-0 py-0 px-4 grid grid-cols-6 md:grid-cols-7 lg:grid-cols-8 gap-4 border-b border-slate-100 dark:border-slate-700 sticky top-16 bg-white dark:bg-slate-900"
:class="{ draggable: onCategoryPage }"
>
<div
class="font-semibold capitalize text-sm py-2 px-0 text-slate-700 dark:text-slate-100 ltr:text-left rtl:text-right col-span-4"
>
{{ $t('HELP_CENTER.TABLE.HEADERS.TITLE') }}
</div>
<div
class="font-semibold capitalize text-sm py-2 px-0 text-slate-700 dark:text-slate-100 text-left"
>
{{ $t('HELP_CENTER.TABLE.HEADERS.CATEGORY') }}
</div>
<div
class="font-semibold capitalize text-sm py-2 px-0 text-slate-700 dark:text-slate-100 text-left hidden lg:block"
>
{{ $t('HELP_CENTER.TABLE.HEADERS.READ_COUNT') }}
</div>
<div
class="font-semibold capitalize text-sm py-2 px-0 text-slate-700 dark:text-slate-100 text-left"
>
{{ $t('HELP_CENTER.TABLE.HEADERS.STATUS') }}
</div>
<div
class="font-semibold capitalize text-sm py-2 px-0 text-slate-700 dark:text-slate-100 text-right hidden md:block"
>
{{ $t('HELP_CENTER.TABLE.HEADERS.LAST_EDITED') }}
</div>
</div>
<draggable
tag="div"
class="border-t-0 px-4"
:disabled="!dragEnabled"
:list="localArticles"
ghost-class="article-ghost-class"
@start="dragging = true"
@end="onDragEnd"
>
<ArticleItem
v-for="article in localArticles"
:id="article.id"
:key="article.id"
:class="{ draggable: onCategoryPage }"
:title="article.title"
:author="article.author"
:category="article.category"
:views="article.views"
:status="article.status"
:updated-at="article.updated_at"
/>
</draggable>
<table-footer
v-if="showArticleFooter"
:current-page="currentPage"
:total-count="totalCount"
:page-size="pageSize"
class="dark:bg-slate-900 sticky bottom-0 border-t-0 px-4"
@page-change="onPageChange"
/>
</div>
</template>
<script>
import ArticleItem from './ArticleItem.vue';
import TableFooter from 'dashboard/components/widgets/TableFooter.vue';
import draggable from 'vuedraggable';
export default {
components: {
ArticleItem,
TableFooter,
draggable,
},
props: {
articles: {
type: Array,
default: () => {},
},
totalCount: {
type: Number,
default: 0,
},
currentPage: {
type: Number,
default: 1,
},
pageSize: {
type: Number,
default: 25,
},
},
data() {
return {
localArticles: [],
};
},
computed: {
dragEnabled() {
// dragging allowed only on category page
return (
this.articles.length > 1 && !this.isFetching && this.onCategoryPage
);
},
onCategoryPage() {
return this.$route.name === 'show_category';
},
showArticleFooter() {
return this.currentPage === 1
? this.totalCount > 25
: this.articles.length > 0;
},
},
watch: {
articles() {
this.localArticles = [...this.articles];
},
},
methods: {
onDragEnd() {
// why reuse the same positons array, instead of creating a new one?
// this ensures that the shuffling happens within the same group
// itself and does not create any new positions and avoid conflict with existing articles
// so if a user sorts on page number 2, and the positions are say [550, 560, 570, 580, 590]
// the new sorted items will be in the same position range as well
const sortedArticlePositions = this.localArticles
.map(article => article.position)
.sort((a, b) => {
// Why sort like this? Glad you asked!
// because JavaScript is the doom of my existence, and if a `compareFn` is not supplied,
// all non-undefined array elements are sorted by converting them to strings
// and comparing strings in UTF-16 code units order.
//
// so an array [20, 10000, 10, 30, 40] will be sorted as [10, 10000, 20, 30, 40]
return a - b;
});
const orderedArticles = this.localArticles.map(article => article.id);
const reorderedGroup = orderedArticles.reduce((obj, key, index) => {
obj[key] = sortedArticlePositions[index];
return obj;
}, {});
this.$emit('reorder', reorderedGroup);
},
onPageChange(page) {
this.$emit('page-change', page);
},
},
};
</script>
<style lang="scss" scoped>
.article-ghost-class {
@apply opacity-50 bg-slate-50 dark:bg-slate-800;
}
</style>