From d46e1344c293e310964e64e4f18badb042b4f788 Mon Sep 17 00:00:00 2001 From: kim Date: Mon, 10 Jun 2024 13:43:07 +0200 Subject: [PATCH 01/10] feat: add global search --- src/api/item.ts | 14 ++++++++++++++ src/api/routes.ts | 32 ++++++++++++++++++++++++++++++-- src/config/keys.ts | 11 +++++++++-- src/hooks/item.ts | 11 +++++++++++ src/hooks/search.test.ts | 10 +++++----- src/hooks/search.ts | 2 +- 6 files changed, 70 insertions(+), 10 deletions(-) diff --git a/src/api/item.ts b/src/api/item.ts index 2c11b81d..2d27d778 100644 --- a/src/api/item.ts +++ b/src/api/item.ts @@ -38,6 +38,7 @@ import { buildPostItemWithThumbnailRoute, buildRecycleItemsRoute, buildRestoreItemsRoute, + buildSearchItems, } from './routes.js'; export const getItem = ( @@ -79,6 +80,19 @@ export const getAccessibleItems = async ( .then(({ data }) => data), ); +export const searchItems = async ( + params: ItemSearchParams, + pagination: PaginationParams, + { API_HOST, axios }: PartialQueryConfigForApi, +) => + verifyAuthentication(() => + axios + .get< + Paginated + >(`${API_HOST}/${buildSearchItems(params, pagination)}`) + .then(({ data }) => data), + ); + export type PostItemPayloadType = Partial & Pick & Partial<{ diff --git a/src/api/routes.ts b/src/api/routes.ts index 0a043603..0a3ddb15 100644 --- a/src/api/routes.ts +++ b/src/api/routes.ts @@ -38,7 +38,7 @@ export const SHORT_LINKS_ROUTE = `${ITEMS_ROUTE}/short-links`; export const SHORT_LINKS_LIST_ROUTE = `${SHORT_LINKS_ROUTE}/list`; export const EMBEDDED_LINKS_ROUTE = `${ITEMS_ROUTE}/embedded-links/metadata`; -export type ItemSearchParams = +export type AccessibleItemSearchParams = | { creatorId?: Member['id']; name?: string; @@ -54,13 +54,29 @@ export type ItemSearchParams = } | undefined; +export type ItemSearchParams = + | { + creatorId?: Member['id']; + keywords?: string[]; + ordering?: 'desc' | 'asc'; + sortBy?: + | 'item.name' + | 'item.type' + | 'item.creator.name' + | 'item.created_at' + | 'item.updated_at'; + permissions?: PermissionLevel[]; + types?: UnionOfConst[]; + } + | undefined; + export type ItemChildrenParams = { ordered?: boolean; types?: UnionOfConst[]; }; export const buildGetAccessibleItems = ( - params: ItemSearchParams, + params: AccessibleItemSearchParams, pagination: PaginationParams, ) => `${ITEMS_ROUTE}/accessible${qs.stringify( @@ -71,6 +87,18 @@ export const buildGetAccessibleItems = ( }, )}`; +export const buildSearchItems = ( + params: ItemSearchParams, + pagination: PaginationParams, +) => + `${ITEMS_ROUTE}/search${qs.stringify( + { ...params, ...pagination }, + { + arrayFormat: 'repeat', + addQueryPrefix: true, + }, + )}`; + export const buildPostItemRoute = (parentId?: UUID) => { let url = ITEMS_ROUTE; if (parentId) { diff --git a/src/config/keys.ts b/src/config/keys.ts index 69bbfa0f..f54adc10 100644 --- a/src/config/keys.ts +++ b/src/config/keys.ts @@ -140,7 +140,10 @@ export const itemKeys = { // shared items shared: () => [...itemKeys.all, 'shared'] as const, - search: (args: { + search: (args: ItemSearchParams, pagination: PaginationParams) => + [...itemKeys.all, 'search', args, pagination] as const, + + publishedSearch: (args: { query?: string; categories?: Category['id'][][]; isPublishedRoot?: boolean; @@ -151,7 +154,11 @@ export const itemKeys = { highlightPostTag?: string; page?: number; }) => - [...itemKeys.all, 'search', { isPublishedRoot: false, ...args }] as const, + [ + ...itemKeys.all, + 'publishedSearch', + { isPublishedRoot: false, ...args }, + ] as const, published: () => { const publishedBaseKey = [...itemKeys.all, 'collections'] as const; diff --git a/src/hooks/item.ts b/src/hooks/item.ts index e810f2b5..13fc79e3 100644 --- a/src/hooks/item.ts +++ b/src/hooks/item.ts @@ -10,6 +10,7 @@ import { useQuery, useQueryClient, } from '@tanstack/react-query'; +import { useState } from 'react'; import { splitRequestByIdsAndReturn } from '../api/axios.js'; import * as Api from '../api/item.js'; @@ -292,6 +293,16 @@ const config = ( }); }, + useSearchItems: (args: ItemSearchParams, pagination: PaginationParams) => { + const [page, setPage] = useState(1); + const finalPagination = { ...pagination, page }; + return useInfiniteQuery({ + queryKey: itemKeys.search(args, finalPagination), + queryFn: () => Api.searchItems(args, finalPagination, queryConfig), + getNextPageParam: () => page, + }); + }, + /** * @deprecated use url alternative when possible * @param id itemId to download content from diff --git a/src/hooks/search.test.ts b/src/hooks/search.test.ts index 7b5333e7..4f0e7f78 100644 --- a/src/hooks/search.test.ts +++ b/src/hooks/search.test.ts @@ -106,7 +106,7 @@ describe('Published Search Hook', () => { const categories = [['mycategoryid']]; const hook = () => hooks.useSearchPublishedItems({ query, categories, page: 1 }); - const key = itemKeys.search({ + const key = itemKeys.publishedSearch({ query, categories, page: 1, @@ -127,7 +127,7 @@ describe('Published Search Hook', () => { it(`does not fetch if no query nor categories is provided`, async () => { const hook = () => hooks.useSearchPublishedItems({}); - const key = itemKeys.search({ page: 1 }); + const key = itemKeys.publishedSearch({ page: 1 }); const endpoints = [{ route, response: RESPONSE }]; const { data, isFetched } = await mockHook({ endpoints, @@ -148,7 +148,7 @@ describe('Published Search Hook', () => { const isPublishedRoot = true; const spy = vi.spyOn(axios, 'post'); - const key = itemKeys.search({ + const key = itemKeys.publishedSearch({ isPublishedRoot, query, categories, @@ -199,7 +199,7 @@ describe('Published Search Hook', () => { const isPublishedRoot = true; const page = 3; const spy = vi.spyOn(axios, 'post'); - const key = itemKeys.search({ + const key = itemKeys.publishedSearch({ isPublishedRoot, query, categories, @@ -248,7 +248,7 @@ describe('Published Search Hook', () => { const query = 'some string'; const categories = [['mycategoryid']]; const isPublishedRoot = true; - const key = itemKeys.search({ + const key = itemKeys.publishedSearch({ isPublishedRoot, query, categories, diff --git a/src/hooks/search.ts b/src/hooks/search.ts index 7341c1e0..a01c4f79 100644 --- a/src/hooks/search.ts +++ b/src/hooks/search.ts @@ -34,7 +34,7 @@ export default (queryConfig: QueryClientConfig) => { } & Api.MeiliSearchProps) => { const debouncedQuery = useDebounce(query, 500); return useQuery({ - queryKey: itemKeys.search({ + queryKey: itemKeys.publishedSearch({ query: debouncedQuery, categories, isPublishedRoot, From 998851a16f1e3d29dfb1b45e77a56c19551feafc Mon Sep 17 00:00:00 2001 From: kim Date: Mon, 10 Jun 2024 13:52:16 +0200 Subject: [PATCH 02/10] refactor: fix param page --- src/config/keys.ts | 4 ++-- src/hooks/item.ts | 15 +++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/config/keys.ts b/src/config/keys.ts index f54adc10..52cddd66 100644 --- a/src/config/keys.ts +++ b/src/config/keys.ts @@ -140,8 +140,8 @@ export const itemKeys = { // shared items shared: () => [...itemKeys.all, 'shared'] as const, - search: (args: ItemSearchParams, pagination: PaginationParams) => - [...itemKeys.all, 'search', args, pagination] as const, + search: (args: ItemSearchParams) => + [...itemKeys.all, 'search', args] as const, publishedSearch: (args: { query?: string; diff --git a/src/hooks/item.ts b/src/hooks/item.ts index 13fc79e3..3335e147 100644 --- a/src/hooks/item.ts +++ b/src/hooks/item.ts @@ -295,11 +295,18 @@ const config = ( useSearchItems: (args: ItemSearchParams, pagination: PaginationParams) => { const [page, setPage] = useState(1); - const finalPagination = { ...pagination, page }; return useInfiniteQuery({ - queryKey: itemKeys.search(args, finalPagination), - queryFn: () => Api.searchItems(args, finalPagination, queryConfig), - getNextPageParam: () => page, + queryKey: itemKeys.search(args), + queryFn: ({ pageParam }) => + Api.searchItems( + args, + { page: pageParam, ...pagination }, + queryConfig, + ), + getNextPageParam: () => { + setPage((p) => p + 1); + return page; + }, }); }, From f9ad81440f2f8da64976c6ca456a462be2ce2d89 Mon Sep 17 00:00:00 2001 From: kim Date: Mon, 10 Jun 2024 13:53:38 +0200 Subject: [PATCH 03/10] refactor: fix --- src/hooks/item.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hooks/item.ts b/src/hooks/item.ts index 3335e147..6ae4d772 100644 --- a/src/hooks/item.ts +++ b/src/hooks/item.ts @@ -14,7 +14,11 @@ import { useState } from 'react'; import { splitRequestByIdsAndReturn } from '../api/axios.js'; import * as Api from '../api/item.js'; -import { ItemChildrenParams, ItemSearchParams } from '../api/routes.js'; +import { + AccessibleItemSearchParams, + ItemChildrenParams, + ItemSearchParams, +} from '../api/routes.js'; import { CONSTANT_KEY_STALE_TIME_MILLISECONDS, DEFAULT_THUMBNAIL_SIZE, @@ -52,7 +56,7 @@ const config = ( * @returns */ useAccessibleItems: ( - params?: ItemSearchParams, + params?: AccessibleItemSearchParams, pagination?: PaginationParams, ) => { const queryClient = useQueryClient(); From fd2bb380a920c6a9564d19ae431e5f8c820454a9 Mon Sep 17 00:00:00 2001 From: kim Date: Mon, 10 Jun 2024 14:04:26 +0200 Subject: [PATCH 04/10] refactor: fix page --- src/hooks/item.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/hooks/item.ts b/src/hooks/item.ts index 6ae4d772..72bd241c 100644 --- a/src/hooks/item.ts +++ b/src/hooks/item.ts @@ -297,9 +297,8 @@ const config = ( }); }, - useSearchItems: (args: ItemSearchParams, pagination: PaginationParams) => { - const [page, setPage] = useState(1); - return useInfiniteQuery({ + useSearchItems: (args: ItemSearchParams, pagination: PaginationParams) => + useInfiniteQuery({ queryKey: itemKeys.search(args), queryFn: ({ pageParam }) => Api.searchItems( @@ -307,12 +306,8 @@ const config = ( { page: pageParam, ...pagination }, queryConfig, ), - getNextPageParam: () => { - setPage((p) => p + 1); - return page; - }, - }); - }, + getNextPageParam: (lastPage, pages) => pages.length, + }), /** * @deprecated use url alternative when possible From 5458625ef4e3d4584f0e5f3ff6b95bfe059c8692 Mon Sep 17 00:00:00 2001 From: kim Date: Mon, 10 Jun 2024 14:05:39 +0200 Subject: [PATCH 05/10] refactor: fix lint --- src/hooks/item.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hooks/item.ts b/src/hooks/item.ts index 72bd241c..5a3e0bdc 100644 --- a/src/hooks/item.ts +++ b/src/hooks/item.ts @@ -10,7 +10,6 @@ import { useQuery, useQueryClient, } from '@tanstack/react-query'; -import { useState } from 'react'; import { splitRequestByIdsAndReturn } from '../api/axios.js'; import * as Api from '../api/item.js'; @@ -306,7 +305,7 @@ const config = ( { page: pageParam, ...pagination }, queryConfig, ), - getNextPageParam: (lastPage, pages) => pages.length, + getNextPageParam: (_lastPage, pages) => pages.length, }), /** From fcf59e554300b2f1dff3e04dd4daf596f26954f2 Mon Sep 17 00:00:00 2001 From: kim Date: Mon, 10 Jun 2024 14:14:19 +0200 Subject: [PATCH 06/10] refactor: add enabled --- src/hooks/item.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/hooks/item.ts b/src/hooks/item.ts index 5a3e0bdc..bc72189a 100644 --- a/src/hooks/item.ts +++ b/src/hooks/item.ts @@ -296,7 +296,11 @@ const config = ( }); }, - useSearchItems: (args: ItemSearchParams, pagination: PaginationParams) => + useSearchItems: ( + args: ItemSearchParams, + pagination: PaginationParams, + options: { enabled?: boolean } = { enabled: true }, + ) => useInfiniteQuery({ queryKey: itemKeys.search(args), queryFn: ({ pageParam }) => @@ -306,6 +310,7 @@ const config = ( queryConfig, ), getNextPageParam: (_lastPage, pages) => pages.length, + enabled: options.enabled, }), /** From 845dc89b6ac77c803dbaafe80681255e7b48029e Mon Sep 17 00:00:00 2001 From: kim Date: Mon, 10 Jun 2024 14:24:17 +0200 Subject: [PATCH 07/10] refactor: add default page number --- src/hooks/item.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/item.ts b/src/hooks/item.ts index bc72189a..ff463469 100644 --- a/src/hooks/item.ts +++ b/src/hooks/item.ts @@ -306,7 +306,7 @@ const config = ( queryFn: ({ pageParam }) => Api.searchItems( args, - { page: pageParam, ...pagination }, + { page: pageParam ?? 1, ...pagination }, queryConfig, ), getNextPageParam: (_lastPage, pages) => pages.length, From 0461ad9428b226020a6499d8023d3c2ddf90523d Mon Sep 17 00:00:00 2001 From: kim Date: Mon, 10 Jun 2024 14:27:27 +0200 Subject: [PATCH 08/10] refactor: add default page number --- src/hooks/item.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/item.ts b/src/hooks/item.ts index ff463469..91b19096 100644 --- a/src/hooks/item.ts +++ b/src/hooks/item.ts @@ -309,7 +309,7 @@ const config = ( { page: pageParam ?? 1, ...pagination }, queryConfig, ), - getNextPageParam: (_lastPage, pages) => pages.length, + getNextPageParam: (_lastPage, pages) => pages.length + 1, enabled: options.enabled, }), From 5f910e5ca98b75509ae6a95eccfa766bcc45139d Mon Sep 17 00:00:00 2001 From: kim Date: Mon, 10 Jun 2024 15:13:40 +0200 Subject: [PATCH 09/10] refactor: add rank --- src/api/routes.ts | 1 + src/hooks/item.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/api/routes.ts b/src/api/routes.ts index 0a3ddb15..3b25236b 100644 --- a/src/api/routes.ts +++ b/src/api/routes.ts @@ -60,6 +60,7 @@ export type ItemSearchParams = keywords?: string[]; ordering?: 'desc' | 'asc'; sortBy?: + | 'rank' | 'item.name' | 'item.type' | 'item.creator.name' diff --git a/src/hooks/item.ts b/src/hooks/item.ts index 91b19096..5bfa66d8 100644 --- a/src/hooks/item.ts +++ b/src/hooks/item.ts @@ -311,6 +311,7 @@ const config = ( ), getNextPageParam: (_lastPage, pages) => pages.length + 1, enabled: options.enabled, + refetchOnWindowFocus: () => false, }), /** From 377a20ecb0ffcc15005408c5c0bfe827eb556c7a Mon Sep 17 00:00:00 2001 From: kim Date: Mon, 10 Jun 2024 15:14:54 +0200 Subject: [PATCH 10/10] refactor: fix --- src/api/item.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/item.ts b/src/api/item.ts index 2d27d778..08c4bd86 100644 --- a/src/api/item.ts +++ b/src/api/item.ts @@ -16,6 +16,7 @@ import { } from '../types.js'; import { verifyAuthentication } from './axios.js'; import { + AccessibleItemSearchParams, GET_OWN_ITEMS_ROUTE, GET_RECYCLED_ITEMS_DATA_ROUTE, ItemChildrenParams, @@ -68,7 +69,7 @@ export const getOwnItems = async ({ ); export const getAccessibleItems = async ( - params: ItemSearchParams, + params: AccessibleItemSearchParams, pagination: PaginationParams, { API_HOST, axios }: PartialQueryConfigForApi, ) =>