Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
<template>
<b-container fluid>
<b-container>
<PageHeader :title="t('myShows.title')">
<AddShowButton />
<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>
</PageHeader>
</b-container>
<b-container>
<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>
<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>
</template>
</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"
/>
</b-container>
</b-container>
</template>
<script lang="ts" setup>
import { PaginatedListResult, usePaginatedList } from '@rokoli/bnb/drf'
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
165
166
167
168
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>