Skip to content

Commit aac68c1

Browse files
refactor pagination to composable (#43)
1 parent b636d1b commit aac68c1

File tree

4 files changed

+258
-206
lines changed

4 files changed

+258
-206
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import type { QTableProps } from 'quasar'
2+
import { useRoute, useRouter } from 'nuxt/app'
3+
import { LocationQueryValue } from 'vue-router'
4+
5+
export default function usePagination() {
6+
const route = useRoute()
7+
const router = useRouter()
8+
const defaultSortBy = 'metadata.lastUpdatedAt'
9+
const defaultDescending = false
10+
const pagination = ref<QTableProps['pagination']>({
11+
rowsNumber: 0,
12+
page: 1,
13+
rowsPerPage: 10,
14+
sortBy: 'metadata.lastUpdatedAt',
15+
descending: false,
16+
})
17+
18+
function initializePagination(total: number = 0) {
19+
console.log('initializePagination', total)
20+
if (!pagination.value) return
21+
const query = { ...route.query }
22+
const limit = query.limit ?? 10
23+
const skip = query.skip ?? 0
24+
pagination.value.rowsPerPage = parseInt(limit as string)
25+
pagination.value.page = parseInt(skip as string) / parseInt(limit as string) + 1
26+
pagination.value.rowsNumber = total
27+
28+
setSortOptions(query)
29+
}
30+
31+
function setSortOptions(query: { [x: string]: LocationQueryValue | LocationQueryValue[] }) {
32+
if (!pagination.value) return
33+
for (const key in query) {
34+
if (key.startsWith('sort')) {
35+
const sortKey = key.replace('sort[', '').replace(']', '')
36+
const sortDirection = query[key] === 'desc' ? 'desc' : 'asc'
37+
pagination.value.sortBy = sortKey
38+
pagination.value.descending = sortDirection === 'desc'
39+
}
40+
}
41+
}
42+
43+
async function onRequest(props: QTableProps, total: number) {
44+
if (!pagination.value) return
45+
if (!props.pagination) return
46+
const { page, rowsPerPage, sortBy, descending } = props.pagination
47+
pagination.value.rowsNumber = total
48+
pagination.value.page = page
49+
pagination.value.rowsPerPage = rowsPerPage
50+
pagination.value.sortBy = sortBy
51+
pagination.value.descending = descending
52+
paginationQuery()
53+
}
54+
55+
function paginationQuery() {
56+
if (!pagination.value) return
57+
if (!pagination.value.page || !pagination.value.rowsPerPage) return
58+
const query = removeSortKey()
59+
const skip = `${(pagination.value.page - 1) * pagination.value.rowsPerPage}`
60+
const limit = `${pagination.value.rowsPerPage}`
61+
let sortKey = defaultSortBy
62+
let sortDirection = defaultDescending ? 'desc' : 'asc'
63+
if (pagination.value.sortBy) {
64+
sortKey = `sort[${pagination.value.sortBy}]`
65+
sortDirection = pagination.value.descending ? 'desc' : 'asc'
66+
}
67+
68+
query[sortKey] = sortDirection
69+
query['skip'] = skip
70+
query['limit'] = limit
71+
72+
router.push({
73+
query,
74+
})
75+
}
76+
77+
function removeSortKey() {
78+
const query = { ...route.query }
79+
for (const key in query) {
80+
if (key.startsWith('sort[')) {
81+
delete query[key]
82+
}
83+
}
84+
return query
85+
}
86+
87+
return { pagination, onRequest, paginationQuery, initializePagination }
88+
}

app/src/pages/mails.vue

Lines changed: 70 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,69 @@
11
<template lang="pug">
22
div
3-
q-card(flat)
4-
q-card-section(horizontal)
5-
q-card-section.full-width(:style="{maxWidth: '50vw', overflow: 'hidden'}")
6-
//v-model:selected="selected"
7-
// selection="multiple"
8-
q-table.tk-sticky-last-column-table(
9-
v-model:pagination="pagination"
10-
title="Mails"
11-
:rows="mails?.data"
12-
row-key="uid"
13-
@request="onRequest"
14-
:rows-per-page-options="[5, 10, 15]"
15-
:columns="columns"
16-
:loading="pending"
17-
rows-per-page-label="Lignes par page"
18-
no-data-label="Aucune donnée"
19-
loading-label="Chargement..."
20-
no-results-label="Aucun résultat"
21-
:pagination-label="(firstRowIndex, endRowIndex, totalRowsNumber) => `${firstRowIndex}-${endRowIndex} sur ${totalRowsNumber} lignes`"
22-
:selected-rows-label="(numberOfRows) => `${numberOfRows} Mails sélectionnées`"
23-
flat
24-
)
25-
template(#body-cell-actions="props")
26-
q-td(:props="props")
27-
q-btn-group(flat rounded)
28-
q-btn(icon="mdi-eye" color="primary" @click="goToMail(props.row)" size="sm" flat)
29-
q-tooltip.text-body2(transition-show="scale" transition-hide="scale") Afficher le ticket
30-
q-btn(icon="mdi-delete" color="primary" @click="deleteMail(props.row)" size="sm" flat)
31-
q-tooltip.text-body2(transition-show="scale" transition-hide="scale") Supprimer le ticket
32-
q-separator(vertical)
33-
q-card-section.full-width(:style="{maxWidth: '50vw', overflow: 'hidden'}")
34-
div.flex.items-center.full-height.justify-center(v-if='!target')
35-
p Selectionnez un email pour afficher son contenu...
36-
q-card(v-else)
37-
q-card-actions
38-
q-toolbar-title(v-text='target?.subject' style='flex: 100 1 0%')
39-
q-space
40-
q-btn(color="negative" icon='mdi-delete' @click="deleteMail(target)")
41-
q-btn(color="primary" icon='mdi-content-save' @click="importMail(target)")
42-
q-card-section.q-pa-xs
43-
q-tabs(v-model="tab" dense)
44-
q-tab(name="email" icon="mdi-mail" label="Email")
45-
q-tab(name="headers" icon="mdi-format-list-text" label="headers")
46-
q-tab(name="raw" icon="mdi-email-newsletter" label="Contenu")
47-
q-tab-panels(v-model="tab")
48-
q-tab-panel.no-padding(name="email")
49-
object.bg-white(:data='"http://localhost:7100/tickets/mails/" + target?.accountId + "/" + target?.seq + "/render?signature=" + target?.signature' style='width: 100%; height: 75vh;')
50-
p Impossible de charger le contenu du mail
51-
a(:href='"http://localhost:7100/tickets/mails/" + target?.accountId + "/" + target?.seq + "/render?signature=" + target?.signature' target='_blank') Lien direct
52-
q-tab-panel.no-padding(name="headers")
53-
q-table(
54-
:rows="target.headers"
55-
:pagination='{rowsPerPage: 12}'
56-
:pagination-label="(firstRowIndex, endRowIndex, totalRowsNumber) => `${firstRowIndex}-${endRowIndex} sur ${totalRowsNumber} lignes`"
57-
rows-per-page-label="Lignes par page"
58-
no-data-label="Aucune donnée"
59-
loading-label="Chargement..."
60-
no-results-label="Aucun résultat"
61-
flat
62-
)
63-
q-tab-panel.no-padding(name="raw")
64-
object.bg-white(:data='"http://localhost:7100/tickets/mails/" + target?.accountId + "/" + target?.seq + "/source?signature=" + target?.signature' style='width: 100%; height: 75vh;')
65-
p Impossible de charger le contenu du mail
66-
a(:href='"http://localhost:7100/tickets/mails/" + target?.accountId + "/" + target?.seq + "/source?signature=" + target?.signature' target='_blank') Lien direct
3+
q-card(flat)
4+
q-card-section(horizontal)
5+
q-card-section.full-width(:style="{maxWidth: '50vw', overflow: 'hidden'}")
6+
//v-model:selected="selected"
7+
// selection="multiple"
8+
q-table.tk-sticky-last-column-table(
9+
v-model:pagination="pagination"
10+
title="Mails"
11+
:rows="mails?.data"
12+
row-key="uid"
13+
@request="onRequest"
14+
:rows-per-page-options="[5, 10, 15]"
15+
:columns="columns"
16+
:loading="pending"
17+
rows-per-page-label="Lignes par page"
18+
no-data-label="Aucune donnée"
19+
loading-label="Chargement..."
20+
no-results-label="Aucun résultat"
21+
:pagination-label="(firstRowIndex, endRowIndex, totalRowsNumber) => `${firstRowIndex}-${endRowIndex} sur ${totalRowsNumber} lignes`"
22+
:selected-rows-label="(numberOfRows) => `${numberOfRows} Mails sélectionnées`"
23+
flat
24+
)
25+
template(#body-cell-actions="props")
26+
q-td(:props="props")
27+
q-btn-group(flat rounded)
28+
q-btn(icon="mdi-eye" color="primary" @click="goToMail(props.row)" size="sm" flat)
29+
q-tooltip.text-body2(transition-show="scale" transition-hide="scale") Afficher le ticket
30+
q-btn(icon="mdi-delete" color="primary" @click="deleteMail(props.row)" size="sm" flat)
31+
q-tooltip.text-body2(transition-show="scale" transition-hide="scale") Supprimer le ticket
32+
q-separator(vertical)
33+
q-card-section.full-width(:style="{maxWidth: '50vw', overflow: 'hidden'}")
34+
div.flex.items-center.full-height.justify-center(v-if='!target')
35+
p Selectionnez un email pour afficher son contenu...
36+
q-card(v-else)
37+
q-card-actions
38+
q-toolbar-title(v-text='target?.subject' style='flex: 100 1 0%')
39+
q-space
40+
q-btn(color="negative" icon='mdi-delete' @click="deleteMail(target)")
41+
q-btn(color="primary" icon='mdi-content-save' @click="importMail(target)")
42+
q-card-section.q-pa-xs
43+
q-tabs(v-model="tab" dense)
44+
q-tab(name="email" icon="mdi-mail" label="Email")
45+
q-tab(name="headers" icon="mdi-format-list-text" label="headers")
46+
q-tab(name="raw" icon="mdi-email-newsletter" label="Contenu")
47+
q-tab-panels(v-model="tab")
48+
q-tab-panel.no-padding(name="email")
49+
object.bg-white(:data='"http://localhost:7100/tickets/mails/" + target?.accountId + "/" + target?.seq + "/render?signature=" + target?.signature' style='width: 100%; height: 75vh;')
50+
p Impossible de charger le contenu du mail
51+
a(:href='"http://localhost:7100/tickets/mails/" + target?.accountId + "/" + target?.seq + "/render?signature=" + target?.signature' target='_blank') Lien direct
52+
q-tab-panel.no-padding(name="headers")
53+
q-table(
54+
:rows="target.headers"
55+
:pagination='{rowsPerPage: 12}'
56+
:pagination-label="(firstRowIndex, endRowIndex, totalRowsNumber) => `${firstRowIndex}-${endRowIndex} sur ${totalRowsNumber} lignes`"
57+
rows-per-page-label="Lignes par page"
58+
no-data-label="Aucune donnée"
59+
loading-label="Chargement..."
60+
no-results-label="Aucun résultat"
61+
flat
62+
)
63+
q-tab-panel.no-padding(name="raw")
64+
object.bg-white(:data='"http://localhost:7100/tickets/mails/" + target?.accountId + "/" + target?.seq + "/source?signature=" + target?.signature' style='width: 100%; height: 75vh;')
65+
p Impossible de charger le contenu du mail
66+
a(:href='"http://localhost:7100/tickets/mails/" + target?.accountId + "/" + target?.seq + "/source?signature=" + target?.signature' target='_blank') Lien direct
6767
</template>
6868

6969
<script lang="ts" setup>
@@ -78,13 +78,9 @@ type Mail = any
7878
// type Mail = components["schemas"]['TicketDto']
7979
const route = useRoute()
8080
const $q = useQuasar()
81-
81+
const { pagination, onRequest, initializePagination } = usePagination();
8282
const selected = ref<Mail[]>([])
83-
const pagination = ref<QTableProps['pagination']>({
84-
page: 1,
85-
rowsPerPage: 10,
86-
rowsNumber: 10,
87-
})
83+
8884
const tab = ref('')
8985
const target = ref<Mail | null>(null)
9086
const { data: mails, refresh, pending, error } = await useHttpApi('/tickets/mails', {
@@ -95,6 +91,10 @@ const { data: mails, refresh, pending, error } = await useHttpApi('/tickets/mail
9591
}
9692
})
9793
})
94+
if (mails.value) {
95+
initializePagination(mails.value?.total)
96+
}
97+
9898
if (error.value) {
9999
console.error(error.value)
100100
}
@@ -223,56 +223,5 @@ const goToMail = async (mail: Mail) => {
223223
}
224224
tab.value = 'email'
225225
}
226-
const onRequest = async (props: QTableProps) => {
227-
const { page, rowsPerPage, sortBy, descending } = props.pagination!
228-
pagination.value!.rowsNumber = mails.value?.total
229-
pagination.value!.page = page
230-
pagination.value!.rowsPerPage = rowsPerPage
231-
pagination.value!.sortBy = sortBy
232-
pagination.value!.descending = descending
233-
paginationQuery()
234-
}
235-
const paginationQuery = () => {
236-
const router = useRouter()
237-
const query = removeSortKey()
238-
const skip = `${(pagination.value?.page! - 1) * pagination.value?.rowsPerPage!}`
239-
const limit = `${pagination.value?.rowsPerPage!}`
240-
query['skip'] = skip
241-
query['limit'] = limit
242-
router.replace({
243-
query
244-
})
245-
}
246-
const removeSortKey = () => {
247-
const route = useRoute()
248-
const query = { ...route.query }
249-
for (const key in query) {
250-
if (key.startsWith('sort[')) {
251-
delete query[key]
252-
}
253-
}
254-
return query
255-
}
256226
257-
onMounted(async () => {
258-
const route = useRoute()
259-
pagination.value!.rowsNumber = mails.value?.total
260-
const query = { ...route.query }
261-
const limit = query.limit ?? 10
262-
const skip = query.skip ?? 0
263-
pagination.value!.rowsPerPage = parseInt(limit as string)
264-
pagination.value!.page = parseInt(skip as string) / parseInt(limit as string) + 1
265-
266-
let sortKey = 'metadata.lastUpdatedAt'
267-
let sortDirection = 'desc'
268-
for (const key in query) {
269-
if (key.startsWith('sort')) {
270-
sortKey = key.replace('sort[', '').replace(']', '')
271-
sortDirection = query[key] === 'desc' ? 'desc' : 'asc'
272-
}
273-
}
274-
pagination.value!.sortBy = sortKey
275-
pagination.value!.descending = sortDirection === 'desc'
276-
paginationQuery()
277-
})
278227
</script>

0 commit comments

Comments
 (0)