Newer
Older
<div>
<PageHeader :title="t('myShows.title')">
<AddShowButton />
</PageHeader>
<div class="tw-flex tw-gap-6 tw-justify-end tw-items-center tw-mb-6">
<Tag v-if="displayMode === 'grid'" class="tw-self-stretch tw-justify-self-start tw-px-3">
{{
t('myShows.showCount', {
count: gridShowResultList.reduce((acc, cur) => acc + cur.items.length, 0),
total: gridShowResultList[0]?.count ?? 0,
})
}}
</Tag>
<Tag v-if="isLoading" role="alert" aria-live="polite" class="tw-px-3 tw-self-stretch">
<span class="tw-flex tw-gap-2 tw-items-center">
<Loading class="tw-h-1" />
{{ t('loadingData', { items: t('show.plural') }) }}
</span>
</Tag>
<span class="tw-mr-auto" />
<FormGroup class="tw-m-0">
<template #iconLeft="attrs">
<icon-system-uicons-search v-bind="attrs" />
</template>
<template #default="attrs">
<input
v-model="searchTerm"
v-bind="attrs"
:aria-label="t('myShows.searchLabel')"
:placeholder="t('myShows.searchPlaceholder')"
</template>
</FormGroup>
<button
class="btn btn-default tw-flex tw-items-center tw-gap-2"
@click="orderFilterDialog.open()"
>
<icon-system-uicons-sort />
{{ t('myShows.sortShows') }}
</button>
<RadioGroup v-model="displayMode" :choices="['table', 'grid']" name="display-mode">
<template #icon="{ value }">
<icon-system-uicons-table-header v-if="value === 'table'" />
<icon-system-uicons-grid-small v-else-if="value === 'grid'" />
</template>
</RadioGroup>
<AEditDialog ref="orderFilterDialog" :title="t('myShows.showOrder')" class="tw-w-min">
<OrderFilter
v-model="order"
translate-base="showFilter.order.choices"
:choices="[
'id',
'slug',
{ name: 'is_active', directions: ['desc', 'asc'] },
{ name: 'updated_at', directions: ['desc', 'asc'] },
'updated_by',
{ name: 'is_owner', directions: ['desc', 'asc'] },
]"
/>
<template #footer="{ close }">
<button type="button" class="btn btn-default tw-min-w-[100px]" @click="close">
{{ t('ok') }}
</button>
</AEditDialog>
</div>
<ShowListTable v-if="displayMode === 'table'" :shows="tableShowResult">
<template #footer>
<div
v-if="tableShowResult.count > 0 || !isLoading"
class="tw-flex tw-items-center tw-px-6 tw-mt-3 tw-py-3 tw-border-0 tw-border-t tw-border-solid tw-border-gray-200 empty:tw-hidden"
>
<PaginationRange v-if="tableShowResult.count > 0" :pagination-data="tableShowResult" />
<FormGroup v-slot="attrs" class="tw-ml-auto tw-m-0 tw-mr-9 last:tw-mr-0">
<label class="tw-flex tw-items-center tw-gap-3 tw-m-0">
<span>{{ t('myShows.itemsPerPage') }}</span>
<input
v-model.lazy="tableShowsPerPage"
type="number"
min="1"
step="1"
v-bind="attrs"
class="tw-w-[80px] tw-self-center"
/>
</label>
</FormGroup>
<Pagination
v-model="tableShowsPage"
:items-per-page="tableShowsPerPage"
:count="tableShowResult.count"
/>
</div>
</template>
</ShowListTable>
<ShowListGrid
v-else
:shows="gridShowResultList"
:has-more="gridShowResult.hasNext"
:split="order[0] === '-is_owner'"
@load-more="loadMore"
/>
</div>
</template>
<script lang="ts" setup>
import { PaginatedListResult, usePaginatedList } from '@rokoli/bnb/drf'
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import { useStorage } from '@vueuse/core'
import { computed, Ref, ref, watch } from 'vue'
import { useI18n } from '@/i18n'
import { computedDebounced } from '@/util'
import { Show } from '@/types'
import { useShowStore } from '@/stores/shows'
import PageHeader from '@/components/PageHeader.vue'
import ShowListTable from '@/components/shows/ShowListTable.vue'
import FormGroup from '@/components/generic/FormGroup.vue'
import ShowListGrid from '@/components/shows/ShowListGrid.vue'
import RadioGroup from '@/components/generic/RadioGroup.vue'
import Loading from '@/components/generic/Loading.vue'
import Tag from '@/components/generic/Tag.vue'
import AEditDialog from '@/components/generic/AEditDialog.vue'
import OrderFilter from '@/components/OrderFilter.vue'
import PaginationRange from '@/components/generic/PaginationRange.vue'
import Pagination from '@/components/generic/Pagination.vue'
import AddShowButton from '@/components/shows/AddShowButton.vue'
const TABLE_SHOWS_PER_PAGE = 12
const GRID_SHOWS_PER_PAGE = 10
type DisplayMode = 'grid' | 'table'
type OrderField = 'is_owner' | 'is_active' | 'slug' | 'updatedAt' | 'updatedBy' | 'id'
type ShowOrder = OrderField | `-${OrderField}`
const { t } = useI18n()
const { listIsolated } = useShowStore()
const orderFilterDialog = ref()
const searchTerm = ref('')
const debouncedSearchTerm = computedDebounced(searchTerm, (q: string) => (q.trim() ? 0.3 : 0))
const order = useStorage<ShowOrder[]>('aura:myShows:order', ['-is_owner', '-is_active', 'slug'])
const query = computed(
() =>
new URLSearchParams({
order: order.value.join(','),
search: debouncedSearchTerm.value.trim(),
}),
)
const displayMode: Ref<DisplayMode> = useStorage<DisplayMode>('aura:myShows:displayMode', 'grid')
const tableShowsPage = ref(1)
const tableShowsPerPage = useStorage('aura:myShows:tableShowsPerPage', TABLE_SHOWS_PER_PAGE)
const { result: tableShowResult, isLoading: isLoadingTableShows } = usePaginatedList(
listIsolated,
tableShowsPage,
tableShowsPerPage,
{ query },
)
const gridShowsPage = ref(1)
const gridShowsPerPage = useStorage('aura:myShows:gridShowsPerPage', GRID_SHOWS_PER_PAGE)
const gridShowResultMap = ref(new Map<number, PaginatedListResult<Show>>())
const gridShowResultList = computed(() => Array.from(gridShowResultMap.value.values()))
const { result: gridShowResult, isLoading: isLoadingGridShows } = usePaginatedList(
listIsolated,
gridShowsPage,
gridShowsPerPage,
{ query },
)
watch(query, () => {
gridShowsPage.value = 1
gridShowResultMap.value.clear()
})
watch(gridShowResult, (newShows: PaginatedListResult<Show>) => {
gridShowResultMap.value.set(newShows.page, newShows)
})
function loadMore() {
if (gridShowResult.value.hasNext) {
gridShowsPage.value += 1
}
}
const isLoading = computed(() => isLoadingTableShows.value || isLoadingGridShows.value)
</script>