usePagination.ts 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // Copyright (C) 2012-2025 Zammad Foundation, https://zammad-foundation.org/
  2. import {
  3. computed,
  4. reactive,
  5. readonly,
  6. ref,
  7. type ComputedRef,
  8. type Ref,
  9. } from 'vue'
  10. import type { QueryHandler } from '#shared/server/apollo/handler/index.ts'
  11. import type {
  12. BaseConnection,
  13. OperationQueryResult,
  14. PaginationVariables,
  15. } from '#shared/types/server/apollo/handler.ts'
  16. import type { OperationVariables } from '@apollo/client/core'
  17. export const usePagination = <
  18. TQueryResult extends OperationQueryResult = OperationQueryResult,
  19. TQueryVariables extends OperationVariables = OperationVariables,
  20. >(
  21. query: QueryHandler<TQueryResult, TQueryVariables>,
  22. resultKey: string,
  23. pageSize: number,
  24. additionalVariables?:
  25. | Ref<Partial<TQueryVariables>>
  26. | ComputedRef<Partial<TQueryVariables>>
  27. | (() => Partial<TQueryVariables>),
  28. ) => {
  29. const pageInfo = computed(() => {
  30. const result: OperationQueryResult = query.result().value || {}
  31. return (result[resultKey] as BaseConnection)?.pageInfo
  32. })
  33. const hasNextPage = computed(() => !!pageInfo.value?.hasNextPage)
  34. const hasPreviousPage = computed(() => !!pageInfo.value?.hasPreviousPage)
  35. const currentPage = computed(() => {
  36. const result: OperationQueryResult = query.result().value || {}
  37. const data = result[resultKey] as BaseConnection
  38. if (!data) return 1
  39. const currentLength = data.edges?.length || 0
  40. return currentLength ? Math.ceil(currentLength / pageSize) : 1
  41. })
  42. const loadingNewPage = ref(false)
  43. return reactive({
  44. pageInfo: readonly(pageInfo),
  45. hasNextPage: readonly(hasNextPage),
  46. hasPreviousPage: readonly(hasPreviousPage),
  47. loadingNewPage: readonly(loadingNewPage),
  48. currentPage,
  49. async fetchPreviousPage() {
  50. try {
  51. loadingNewPage.value = true
  52. await query.fetchMore({
  53. variables: {
  54. pageSize,
  55. cursor: pageInfo.value?.startCursor,
  56. } as Partial<TQueryVariables & PaginationVariables>,
  57. })
  58. } finally {
  59. loadingNewPage.value = false
  60. }
  61. },
  62. async fetchNextPage() {
  63. try {
  64. loadingNewPage.value = true
  65. const nextAdditionalVariables =
  66. (typeof additionalVariables === 'function'
  67. ? additionalVariables()
  68. : additionalVariables?.value) || {}
  69. await query.fetchMore({
  70. variables: {
  71. pageSize,
  72. cursor: pageInfo.value?.endCursor,
  73. ...nextAdditionalVariables,
  74. } as Partial<TQueryVariables & PaginationVariables>,
  75. })
  76. } finally {
  77. loadingNewPage.value = false
  78. }
  79. },
  80. })
  81. }