diff --git a/src/components/sectionList/filters/filterSelectors/ModelFilter.tsx b/src/components/sectionList/filters/filterSelectors/ModelFilter.tsx
index eff0b634..c2f14d0a 100644
--- a/src/components/sectionList/filters/filterSelectors/ModelFilter.tsx
+++ b/src/components/sectionList/filters/filterSelectors/ModelFilter.tsx
@@ -1,7 +1,7 @@
import { useDataQuery } from '@dhis2/app-runtime'
import React, { useCallback, useRef, useState } from 'react'
-import type { Query } from '../../../../types'
-import { Pager } from '../../../../types/generated'
+import { useInfiniteDataQuery } from '../../../../lib/query'
+import type { ResultQuery } from '../../../../types'
import { Option, SearchableSingleSelect } from '../../../SearchableSingleSelect'
function computeDisplayOptions({
@@ -34,27 +34,15 @@ function computeDisplayOptions({
}))
}
-type ModelQuery = {
- result: Query[keyof Query]
-}
-
type OptionResult = {
id: string
displayName: string
}
-type OptionsResult = {
- result: {
- pager: Pager
- } & { [key: string]: OptionResult[] }
-}
-
-type PagedResult = { pager: Pager } & OptionsResult
-
const createInitialOptionQuery = (
resource: string,
selected?: string
-): ModelQuery => ({
+): ResultQuery => ({
result: {
resource: resource,
id: selected,
@@ -69,7 +57,7 @@ export interface ModelSingleSelectProps {
onChange: ({ selected }: { selected: string | undefined }) => void
selected?: string
placeholder: string
- query: Query
+ query: ResultQuery
}
export const ModelFilterSelect = ({
@@ -82,7 +70,6 @@ export const ModelFilterSelect = ({
// We're using this value only when imperatively calling `refetch`,
// nothing that depends on the render-cycle depends on this value
const filterRef = useRef
()
- const pageRef = useRef(0)
const [initialQuery] = useState(() =>
createInitialOptionQuery(query.result.resource, selected)
@@ -101,9 +88,9 @@ export const ModelFilterSelect = ({
// the page with the selected option hasn't been reached yet or when
// filtering)
const [selectedOption, setSelectedOption] = useState()
-
- const optionsQueryResult = useDataQuery(query)
- const { refetch, data } = optionsQueryResult
+ const optionsQueryResult = useInfiniteDataQuery(query)
+ // const optionsQueryResult = useDataQuery(query)
+ const { refetch, data, incrementPage } = optionsQueryResult
const pager = data?.result.pager
const page = pager?.page || 0
@@ -111,21 +98,15 @@ export const ModelFilterSelect = ({
const refetchWithFilter = useCallback(
({ value }: { value: string }) => {
- pageRef.current = 1
filterRef.current = value ? `displayName:ilike:${value}` : undefined
refetch({
- page: pageRef.current,
- filter: value ? filterRef.current : undefined,
+ page: 1,
+ filter: filterRef.current,
})
},
[refetch]
)
- const incrementPage = useCallback(() => {
- pageRef.current = page + 1
- refetch({ page: pageRef.current, filter: filterRef.current })
- }, [refetch, page])
-
const loading =
optionsQueryResult.fetching ||
optionsQueryResult.loading ||
@@ -145,33 +126,36 @@ export const ModelFilterSelect = ({
})
return (
- {
- if (selected === selectedOption?.id) {
- setSelectedOption(undefined)
- } else {
- const option = options.find(({ id }) => id === selected)
- setSelectedOption(option)
- }
-
- onChange({ selected: selected })
- }}
- onEndReached={incrementPage}
- options={displayOptions}
- selected={selected}
- showEndLoader={!loading && page < pageCount}
- onFilterChange={refetchWithFilter}
- loading={loading}
- error={error}
- onRetryClick={() => {
- refetch({
- page: pageRef.current,
- filter: filterRef.current,
- })
- }}
- />
+
+ {
+ if (selected === selectedOption?.id) {
+ setSelectedOption(undefined)
+ } else {
+ const option = options.find(({ id }) => id === selected)
+ setSelectedOption(option)
+ }
+
+ onChange({ selected: selected })
+ }}
+ onEndReached={incrementPage}
+ options={displayOptions}
+ selected={selected}
+ showEndLoader={!loading && page < pageCount}
+ onFilterChange={refetchWithFilter}
+ loading={loading}
+ error={error}
+ onRetryClick={() => {
+ refetch({
+ page: page,
+ filter: filterRef.current,
+ })
+ }}
+ />
+
)
}
diff --git a/src/components/sectionList/filters/filterSelectors/createdFilterDataQuery.ts b/src/components/sectionList/filters/filterSelectors/createdFilterDataQuery.ts
index f527c3ce..108c66ce 100644
--- a/src/components/sectionList/filters/filterSelectors/createdFilterDataQuery.ts
+++ b/src/components/sectionList/filters/filterSelectors/createdFilterDataQuery.ts
@@ -1,6 +1,6 @@
-import { Query } from '../../../../types'
+import { ResultQuery } from '../../../../types'
-export const createFilterDataQuery = (resource: string): Query => ({
+export const createFilterDataQuery = (resource: string): ResultQuery => ({
result: {
resource: resource,
params: (params) => ({
diff --git a/src/lib/query/index.ts b/src/lib/query/index.ts
new file mode 100644
index 00000000..572da64c
--- /dev/null
+++ b/src/lib/query/index.ts
@@ -0,0 +1 @@
+export * from './useInfiniteDataQuery'
diff --git a/src/lib/query/useInfiniteDataQuery.ts b/src/lib/query/useInfiniteDataQuery.ts
new file mode 100644
index 00000000..41ff629f
--- /dev/null
+++ b/src/lib/query/useInfiniteDataQuery.ts
@@ -0,0 +1,73 @@
+import { useDataQuery } from '@dhis2/app-runtime'
+import { useCallback, useEffect, useMemo, useState } from 'react'
+import { ResultQuery, WrapQueryResponse } from '../../types'
+import { Pager } from '../../types/generated'
+
+type PagerObject = {
+ pager: Pager
+}
+
+type PagedResponse = PagerObject & { [key: string]: TData[] }
+
+type InfiniteQueryResult = WrapQueryResponse>
+
+type QueryOptions = Parameters[1]
+type InfiniteQueryOptions = QueryOptions & {
+ dataResultKey?: string
+}
+export const useInfiniteDataQuery = (
+ query: ResultQuery,
+ options?: InfiniteQueryOptions
+) => {
+ const [allResult, setAllResult] = useState([])
+
+ let queryOptions: QueryOptions = undefined
+ let dataKey = query.result.resource
+ if (options) {
+ const { dataResultKey, ...opts } = options
+ dataKey = dataResultKey || query.result.resource
+ queryOptions = opts
+ }
+
+ const queryResult = useDataQuery>(
+ query,
+ queryOptions
+ )
+ const { refetch, data } = queryResult
+
+ const pager = data?.result.pager
+ const page = pager?.page || 0
+ const pageCount = pager?.pageCount || 0
+
+ useEffect(() => {
+ const result = data?.result[dataKey]
+ if (result) {
+ setAllResult((prev) => {
+ const pager = data.result.pager
+ if (pager.page === 1) {
+ return data.result[dataKey]
+ }
+ return [...prev, ...data.result[dataKey]]
+ })
+ }
+ }, [data, dataKey, setAllResult])
+
+ const incrementPage = useCallback(() => {
+ refetch({ page: page + 1 })
+ }, [refetch, page])
+
+ const newData = useMemo(() => {
+ return {
+ result: {
+ ...data?.result,
+ [dataKey]: allResult,
+ },
+ }
+ }, [allResult, data, dataKey])
+ return {
+ ...queryResult,
+ data: newData,
+ incrementPage,
+ hasNextPage: page < pageCount,
+ }
+}
diff --git a/src/types/query.ts b/src/types/query.ts
index 033fa358..533dcf2e 100644
--- a/src/types/query.ts
+++ b/src/types/query.ts
@@ -4,8 +4,14 @@ export type QueryResponse = ReturnType
export type Query = Parameters[0]
+export type ResourceQuery = Query[keyof Query]
+
export type QueryRefetchFunction = QueryResponse['refetch']
export type WrapQueryResponse = {
[K in S]: T
}
+
+export type ResultQuery = {
+ result: ResourceQuery
+}