diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/api/index.ts b/src/frontend/apps/impress/src/features/docs/doc-management/api/index.ts index d3f041e0..e710a364 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-management/api/index.ts +++ b/src/frontend/apps/impress/src/features/docs/doc-management/api/index.ts @@ -9,5 +9,5 @@ export * from './useDocsFavorite'; export * from './useDuplicateDoc'; export * from './useMoveDoc'; export * from './useRestoreDoc'; -export * from './useSubDocs'; export * from './useUpdateDoc'; +export * from './useSearchDocs'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/api/searchDocs.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/api/searchDocs.tsx deleted file mode 100644 index 68660f77..00000000 --- a/src/frontend/apps/impress/src/features/docs/doc-management/api/searchDocs.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; - -import { APIError, APIList, errorCauses, fetchAPI } from '@/api'; -import { KEY_LIST_DOC } from '@/docs/doc-management'; - -import { Doc } from '../types'; - -export type DocsParams = { - q: string; -}; - -export const constructParams = (params: DocsParams): URLSearchParams => { - const searchParams = new URLSearchParams(); - - if (params.q.length > 0) { - searchParams.set('q', params.q); - } else { - searchParams.set('q', '*'); - } - - return searchParams; -}; - -export type DocsResponse = APIList; -export const getDocs = async (params: DocsParams): Promise => { - const searchParams = constructParams(params); - const response = await fetchAPI( - `documents/search/?${searchParams.toString()}`, - ); - - if (!response.ok) { - throw new APIError('Failed to get the docs', await errorCauses(response)); - } - - return response.json() as Promise; -}; - -export const useSearchDocs = (params: DocsParams) => { - return useQuery({ - queryKey: [KEY_LIST_DOC, 'search', params], - queryFn: () => getDocs(params), - }); -}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/api/useSearchDocs.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/api/useSearchDocs.tsx new file mode 100644 index 00000000..9ea2e467 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-management/api/useSearchDocs.tsx @@ -0,0 +1,81 @@ +import { useQuery } from '@tanstack/react-query'; + +import { + APIError, + APIList, + errorCauses, + fetchAPI, + useAPIInfiniteQuery, +} from '@/api'; +import { Doc } from '@/docs/doc-management'; +import { DocSearchTarget } from '@/docs/doc-search'; + +export type SearchDocsParams = { + page: number; + q: string; + target?: DocSearchTarget; + parentPath?: string; +}; + +const constructParams = ({ + q, + page, + target, + parentPath, +}: SearchDocsParams): URLSearchParams => { + const searchParams = new URLSearchParams(); + + searchParams.set('q', q); + + if (target === DocSearchTarget.CURRENT && parentPath) { + searchParams.set('path', parentPath); + } + if (page) { + searchParams.set('page', page.toString()); + } + + return searchParams; +}; + +const searchDocs = async ({ + q, + page, + target, + parentPath, +}: SearchDocsParams): Promise> => { + const searchParams = constructParams({ q, page, target, parentPath }); + const response = await fetchAPI( + `documents/search/?${searchParams.toString()}`, + ); + + if (!response.ok) { + throw new APIError('Failed to get the docs', await errorCauses(response)); + } + + return response.json() as Promise>; +}; + +export const KEY_LIST_SEARCH_DOC = 'search-docs'; + +export const useSearchDocs = ( + { q, page, target, parentPath }: SearchDocsParams, + queryConfig?: { enabled?: boolean }, +) => { + return useQuery, APIError, APIList>({ + queryKey: [KEY_LIST_SEARCH_DOC, 'search', { q, page, target, parentPath }], + queryFn: () => searchDocs({ q, page, target, parentPath }), + ...queryConfig, + }); +}; + +export const useInfiniteSearchDocs = ( + params: SearchDocsParams, + queryConfig?: { enabled?: boolean }, +) => { + return useAPIInfiniteQuery( + KEY_LIST_SEARCH_DOC, + searchDocs, + params, + queryConfig, + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchContent.tsx b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchContent.tsx index 08408392..e6b09800 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchContent.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchContent.tsx @@ -1,14 +1,13 @@ import { t } from 'i18next'; -import { useEffect, useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { InView } from 'react-intersection-observer'; import { Box } from '@/components/'; import { QuickSearchData, QuickSearchGroup } from '@/components/quick-search'; -import { useSearchDocs } from '@/docs/doc-management/api/searchDocs'; +import { useInfiniteSearchDocs } from '@/docs/doc-management/api/useSearchDocs'; import { Doc } from '../../doc-management'; -import { DocSearchFiltersValues } from './DocSearchFilters'; import { DocSearchItem } from './DocSearchItem'; type DocSearchContentProps = { @@ -30,7 +29,15 @@ export const DocSearchContent = ({ renderSearchElement, isSearchNotMandatory, }: DocSearchContentProps) => { - const { data, isFetching, isRefetching, isLoading } = useSearchDocs({ + const { + data, + isFetching, + isRefetching, + isLoading, + fetchNextPage, + hasNextPage, + } = useInfiniteSearchDocs({ + page: 1, q: search, }); diff --git a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx index e0068387..bb14f1c1 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx @@ -133,7 +133,6 @@ const DocSearchModalGlobal = ({ {isDocPage && target === DocSearchTarget.CURRENT && ( } diff --git a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchSubPageContent.tsx b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchSubPageContent.tsx index 7d82005f..7d9747ce 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchSubPageContent.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchSubPageContent.tsx @@ -4,13 +4,12 @@ import React, { useEffect, useState } from 'react'; import { InView } from 'react-intersection-observer'; import { QuickSearchData, QuickSearchGroup } from '@/components/quick-search'; -import { Doc, useInfiniteSubDocs } from '@/docs/doc-management'; - -import { DocSearchFiltersValues } from './DocSearchFilters'; +import { Doc } from '@/docs/doc-management'; +import { useInfiniteSearchDocs } from '@/docs/doc-management/api/useSearchDocs'; +import { DocSearchTarget } from '@/docs/doc-search'; type DocSearchSubPageContentProps = { search: string; - filters: DocSearchFiltersValues; onSelect: (doc: Doc) => void; onLoadingChange?: (loading: boolean) => void; renderElement: (doc: Doc) => React.ReactNode; @@ -18,7 +17,6 @@ type DocSearchSubPageContentProps = { export const DocSearchSubPageContent = ({ search, - filters, onSelect, onLoadingChange, renderElement, @@ -32,17 +30,18 @@ export const DocSearchSubPageContent = ({ isLoading, fetchNextPage: subDocsFetchNextPage, hasNextPage: subDocsHasNextPage, - } = useInfiniteSubDocs( + } = useInfiniteSearchDocs( { + q: search, page: 1, - title: search, - ...filters, - parent_id: treeContext?.root?.id ?? '', + target: DocSearchTarget.CURRENT, + parentPath: treeContext?.root?.path, }, { - enabled: !!treeContext?.root?.id, + enabled: !!treeContext?.root?.path, }, ); + const [docsData, setDocsData] = useState>({ groupName: '', elements: [], @@ -58,16 +57,6 @@ export const DocSearchSubPageContent = ({ const subDocs = subDocsData?.pages.flatMap((page) => page.results) || []; - if (treeContext?.root) { - const isRootTitleIncludeSearch = treeContext.root?.title - ?.toLowerCase() - .includes(search.toLowerCase()); - - if (isRootTitleIncludeSearch) { - subDocs.unshift(treeContext.root); - } - } - setDocsData({ groupName: subDocs.length > 0 ? t('Select a doc') : '', elements: search ? subDocs : [],