diff --git a/config/packages/api_platform.yaml b/config/packages/api_platform.yaml index 4b2b414..c686cc6 100644 --- a/config/packages/api_platform.yaml +++ b/config/packages/api_platform.yaml @@ -5,6 +5,8 @@ api_platform: stateless: true cache_headers: vary: ['Content-Type', 'Authorization', 'Origin'] + pagination_client_items_per_page: true + pagination_maximum_items_per_page: 100 formats: json: ['application/json'] jsonld: ['application/ld+json'] diff --git a/frontend/components/ui/UiDataTable.vue b/frontend/components/ui/UiDataTable.vue new file mode 100644 index 0000000..fa3572e --- /dev/null +++ b/frontend/components/ui/UiDataTable.vue @@ -0,0 +1,230 @@ + + + diff --git a/frontend/composables/useDataTableServerState.ts b/frontend/composables/useDataTableServerState.ts new file mode 100644 index 0000000..36697fd --- /dev/null +++ b/frontend/composables/useDataTableServerState.ts @@ -0,0 +1,102 @@ +import { ref, watch } from 'vue' +import { useApi } from '~/composables/useApi' + +type FilterValue = string | number | boolean | null + +export interface UseDataTableServerStateOptions { + initialPerPage?: number + debounceMs?: number +} + +export function useDataTableServerState>( + endpoint: string, + initialFilters: Record = {}, + options: UseDataTableServerStateOptions = {} +) { + const api = useApi() + + const debounceMs = options.debounceMs ?? 300 + const initialPerPage = options.initialPerPage ?? 10 + + const items = ref([]) as { value: T[] } + const totalItems = ref(0) + const page = ref(1) + const perPage = ref(initialPerPage) + const filters = ref>({ ...initialFilters }) + const loading = ref(false) + + let debounceTimer: ReturnType | null = null + let requestToken = 0 + + const buildQueryParams = (): Record => { + const params: Record = { + page: page.value, + itemsPerPage: perPage.value + } + for (const [key, value] of Object.entries(filters.value)) { + if (value === '' || value === null) continue + params[key] = value as string | number | boolean + } + return params + } + + const fetchItems = async (): Promise => { + const currentToken = ++requestToken + loading.value = true + try { + const data = await api.get<{ member: T[]; totalItems: number }>( + endpoint, + buildQueryParams(), + { + toast: false, + headers: { Accept: 'application/ld+json' } + } + ) + if (currentToken !== requestToken) return + items.value = data?.member ?? [] + totalItems.value = data?.totalItems ?? 0 + } finally { + if (currentToken === requestToken) { + loading.value = false + } + } + } + + const reload = (): void => { + if (debounceTimer) { + clearTimeout(debounceTimer) + debounceTimer = null + } + void fetchItems() + } + + const scheduleReload = (): void => { + if (debounceTimer) clearTimeout(debounceTimer) + debounceTimer = setTimeout(() => { + debounceTimer = null + void fetchItems() + }, debounceMs) + } + + watch([page, perPage], () => { + reload() + }) + + watch(filters, () => { + if (page.value !== 1) { + page.value = 1 + return + } + scheduleReload() + }, { deep: true }) + + return { + items, + totalItems, + page, + perPage, + filters, + loading, + reload + } +} diff --git a/frontend/pages/reception/finish-reception.vue b/frontend/pages/reception/finish-reception.vue index abf79a0..999dead 100644 --- a/frontend/pages/reception/finish-reception.vue +++ b/frontend/pages/reception/finish-reception.vue @@ -5,42 +5,50 @@
-
-
-
Numéro
-
Date et heure
-
Fournisseur
-
Adresse
-
Type réception
-
Poids
-
-
+ -
{{ reception.identificationNumber}}
-
{{ formatDate(reception.receptionDate) }}
-
{{ reception.supplier?.name }}
-
{{ reception.address?.fullAddress }}
-
{{ reception.receptionType?.label }}
-
{{ formatWeighing(reception) }}
-
+ + +