From 3912736018e58727a493e9412f45bd70622a05aa Mon Sep 17 00:00:00 2001 From: John Ballesteros Date: Thu, 12 Dec 2024 15:24:35 +0800 Subject: [PATCH] refactor: working pillar items --- .../pillar-items-dropdown-content.tsx | 64 ++++++++++++------ src/search/core/schemas.ts | 5 +- src/search/core/types.ts | 2 +- src/search/data/get-pillar-items.ts | 66 ++++++++++--------- src/search/pages/pillar-page.tsx | 2 + src/search/utils/create-input-items.ts | 11 +++- 6 files changed, 93 insertions(+), 57 deletions(-) diff --git a/src/search/components/pillar-items-dropdown-content.tsx b/src/search/components/pillar-items-dropdown-content.tsx index bbccd52..7235800 100644 --- a/src/search/components/pillar-items-dropdown-content.tsx +++ b/src/search/components/pillar-items-dropdown-content.tsx @@ -23,7 +23,6 @@ import { PillarSearchParams, TPillarItem, } from '@/search/core/types'; -import { convertSlugToTitle } from '@/search/utils/convert-slug-to-title'; import { createPillarItemHref } from '@/search/utils/create-pillar-item-href'; import { createToggledPillarItemSearchParam } from '@/search/utils/create-toggled-pillar-item-search-param'; import { hiddenPillarItemsAtom } from '@/search/core/atoms'; @@ -31,7 +30,7 @@ import { getPillarItems } from '@/search/data/get-pillar-items'; import { usePillarRoutesContext } from '@/search/state/contexts/pillar-routes-context'; -const ITEMS_PER_PAGE = 10; +const ITEMS_PER_PAGE = 20; interface Props { nav: string; @@ -39,12 +38,20 @@ interface Props { params: PillarParams; searchParams: PillarSearchParams; pillarSlug: string; + pillarItems: TPillarItem[]; activeItems: TPillarItem[]; } export const PillarItemsDropdownContent = (props: Props) => { - const { pillarSlug, activeItems, nav, pillarInfo, params, searchParams } = - props; + const { + pillarSlug, + activeItems, + nav, + pillarInfo, + pillarItems, + params, + searchParams, + } = props; const router = useRouter(); const queryClient = useQueryClient(); @@ -62,12 +69,13 @@ export const PillarItemsDropdownContent = (props: Props) => { const hiddenItems = hiddenItemsMap[pillarSlug] || []; const list = useAsyncList({ - async load({ cursor, filterText }) { + async load({ cursor = ITEMS_PER_PAGE, filterText }) { + const page = Math.floor(cursor / ITEMS_PER_PAGE) + 1; const queryProps: GetPillarItemsProps = { - nav: '', + nav, pillar: pillarSlug, - query: filterText || '', - page: cursor, + query: filterText || undefined, + page, limit: ITEMS_PER_PAGE, }; @@ -76,7 +84,7 @@ export const PillarItemsDropdownContent = (props: Props) => { queryFn: async () => getPillarItems(queryProps), }); - const start = cursor || 0; + const start = cursor || ITEMS_PER_PAGE; const nextCursor = start + ITEMS_PER_PAGE; return { @@ -86,10 +94,24 @@ export const PillarItemsDropdownContent = (props: Props) => { }, }); + const pillarItemsSet = useMemo( + () => new Set(pillarItems.map(({ label }) => label)), + [pillarItems], + ); + + const dropdownItems = useMemo( + () => [ + ...hiddenItems.reverse(), + ...list.items.filter((itemLabel) => !pillarItemsSet.has(itemLabel)), + ], + // eslint-disable-next-line react-hooks/exhaustive-deps + [list.items.length], + ); + useEffect(() => { list.reload(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [hiddenItems]); + }, [hiddenItems.length]); const itemSlugsSet = useMemo( () => new Set(activeItems.map(({ label }) => normalizeString(label))), @@ -121,7 +143,9 @@ export const PillarItemsDropdownContent = (props: Props) => { }; useEffect(() => { - list.setFilterText(query); + if (query) { + list.setFilterText(query); + } // eslint-disable-next-line react-hooks/exhaustive-deps }, [query]); @@ -134,17 +158,17 @@ export const PillarItemsDropdownContent = (props: Props) => { }, }); - const pillarName = convertSlugToTitle(pillarSlug); - return ( <> : null} /> { })} > - {list.items.length > 0 ? ( - list.items.map((label, i) => { + {dropdownItems.length > 0 ? ( + dropdownItems.map((label, i) => { const isActive = itemSlugsSet.has(normalizeString(label)); return ( @@ -174,7 +198,7 @@ export const PillarItemsDropdownContent = (props: Props) => { >
{label}
diff --git a/src/search/core/schemas.ts b/src/search/core/schemas.ts index afc9984..6231b1a 100644 --- a/src/search/core/schemas.ts +++ b/src/search/core/schemas.ts @@ -85,8 +85,9 @@ export const dtoToPillarInfo = (dto: PillarInfoDto): TPillarInfo => { }; export const pillarItemsResponseDtoSchema = z.object({ - success: z.boolean(), - message: z.string(), + page: z.number(), + count: z.number(), + total: z.number(), data: z.array(z.string()), }); export type PillarItemsResponseDto = z.infer< diff --git a/src/search/core/types.ts b/src/search/core/types.ts index 5ffb9e1..dd7d8ae 100644 --- a/src/search/core/types.ts +++ b/src/search/core/types.ts @@ -17,7 +17,7 @@ export interface GetPillarInfoProps extends PillarParams { export interface GetPillarItemsProps { nav: string; pillar: string; - query: string; + query?: string; page?: number; limit?: number; } diff --git a/src/search/data/get-pillar-items.ts b/src/search/data/get-pillar-items.ts index 81e5de7..86690b2 100644 --- a/src/search/data/get-pillar-items.ts +++ b/src/search/data/get-pillar-items.ts @@ -1,38 +1,40 @@ -// import { FRONTEND_URL } from '@/shared/core/envs'; -// import { mwGET } from '@/shared/utils/mw-get'; - -// import { pillarItemsResponseDtoSchema } from '@/search/core/schemas'; -// import { GetPillarItemsProps } from '@/search/core/types'; - -// export const getPillarItems = async (props: GetPillarItemsProps): Promise => { -// const { nav, pillar, query, page = 1, limit = 20 } = props; - -// const url = new URL(`${FRONTEND_URL}/search/pillar-items`); -// const searchParams = new URLSearchParams({ -// nav, -// pillar, -// query, -// page: `${page}`, -// limit: `${limit}`, -// }); -// url.search = searchParams.toString(); - -// const response = await mwGET({ -// url: url.toString(), -// label: 'getPillarItems', -// responseSchema: pillarItemsResponseDtoSchema, -// }); - -// return response.data; -// }; +import { MW_URL } from '@/shared/core/envs'; +import { mwGET } from '@/shared/utils/mw-get'; +import { pillarItemsResponseDtoSchema } from '@/search/core/schemas'; import { GetPillarItemsProps } from '@/search/core/types'; -import { fakePillarItems } from '@/search/testutils/fake-pillar-items'; - export const getPillarItems = async ( - _props: GetPillarItemsProps, + props: GetPillarItemsProps, ): Promise => { - await new Promise((r) => setTimeout(r, 500)); - return fakePillarItems(); + const { nav, pillar, query, page = 1, limit = 20 } = props; + + const url = new URL(`${MW_URL}/search/pillar/items`); + const searchParams = new URLSearchParams({ + nav, + pillar, + page: `${page}`, + limit: `${limit}`, + }); + if (query) searchParams.set('query', query); + url.search = searchParams.toString(); + + const response = await mwGET({ + url: url.toString(), + label: 'getPillarItems', + responseSchema: pillarItemsResponseDtoSchema, + }); + + return response.data; }; + +// import { GetPillarItemsProps } from '@/search/core/types'; + +// import { fakePillarItems } from '@/search/testutils/fake-pillar-items'; + +// export const getPillarItems = async ( +// _props: GetPillarItemsProps, +// ): Promise => { +// await new Promise((r) => setTimeout(r, 500)); +// return fakePillarItems(); +// }; diff --git a/src/search/pages/pillar-page.tsx b/src/search/pages/pillar-page.tsx index 1d41952..7f52503 100644 --- a/src/search/pages/pillar-page.tsx +++ b/src/search/pages/pillar-page.tsx @@ -66,6 +66,7 @@ export const PillarPage = async ({ nav, params, searchParams }: Props) => { params={params} searchParams={searchParams} pillarSlug={params.pillar} + pillarItems={mainItems} activeItems={activeItems.include} /> } @@ -92,6 +93,7 @@ export const PillarPage = async ({ nav, params, searchParams }: Props) => { params={params} searchParams={searchParams} pillarSlug={slug} + pillarItems={items} activeItems={activeItems[slug] || []} /> } diff --git a/src/search/utils/create-input-items.ts b/src/search/utils/create-input-items.ts index 2ace3c0..e95c0c8 100644 --- a/src/search/utils/create-input-items.ts +++ b/src/search/utils/create-input-items.ts @@ -1,4 +1,8 @@ -import { normalizeString } from '@/shared/utils/normalize-string'; +import { capitalize } from '@/shared/utils/capitalize'; +import { + denormalizeString, + normalizeString, +} from '@/shared/utils/normalize-string'; import { TPillarItem } from '@/search/core/types'; @@ -28,5 +32,8 @@ export const createInputItems = ( ...altItemsArray, ]; - return items; + return items.map((item) => ({ + ...item, + label: capitalize(denormalizeString(item.label)), + })); };