Skip to content

Commit

Permalink
refactor: working pillar items
Browse files Browse the repository at this point in the history
  • Loading branch information
johnshift committed Dec 12, 2024
1 parent a114c44 commit 3912736
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 57 deletions.
64 changes: 44 additions & 20 deletions src/search/components/pillar-items-dropdown-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,35 @@ 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';
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;
pillarInfo: TPillarInfo;
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();
Expand All @@ -62,12 +69,13 @@ export const PillarItemsDropdownContent = (props: Props) => {
const hiddenItems = hiddenItemsMap[pillarSlug] || [];

const list = useAsyncList<string, number>({
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,
};

Expand All @@ -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 {
Expand All @@ -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))),
Expand Down Expand Up @@ -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]);

Expand All @@ -134,17 +158,17 @@ export const PillarItemsDropdownContent = (props: Props) => {
},
});

const pillarName = convertSlugToTitle(pillarSlug);

return (
<>
<Input
radius="sm"
placeholder={`Search ${pillarName} ...`}
placeholder={
list.isLoading ? 'Loading more items ...' : `Search ${pillarSlug} ...`
}
value={query}
onChange={handleQueryChange}
aria-label={`Search ${pillarName}`}
isDisabled={isPendingPillarRoute}
aria-label={`Search ${pillarSlug}`}
isDisabled={isPendingPillarRoute || list.isLoading}
endContent={list.isLoading ? <Spinner size="sm" color="white" /> : null}
/>
<ScrollShadow
Expand All @@ -153,12 +177,12 @@ export const PillarItemsDropdownContent = (props: Props) => {
})}
>
<Listbox
aria-label={`${pillarName} items`}
aria-label={`${pillarSlug} items`}
disabledKeys={['no-results']}
onAction={onAction}
>
{list.items.length > 0 ? (
list.items.map((label, i) => {
{dropdownItems.length > 0 ? (
dropdownItems.map((label, i) => {
const isActive = itemSlugsSet.has(normalizeString(label));

return (
Expand All @@ -174,7 +198,7 @@ export const PillarItemsDropdownContent = (props: Props) => {
>
<div
key={label}
ref={i === list.items.length - 1 ? inViewRef : undefined}
ref={i === dropdownItems.length - 1 ? inViewRef : undefined}
>
{label}
</div>
Expand Down
5 changes: 3 additions & 2 deletions src/search/core/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand Down
2 changes: 1 addition & 1 deletion src/search/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export interface GetPillarInfoProps extends PillarParams {
export interface GetPillarItemsProps {
nav: string;
pillar: string;
query: string;
query?: string;
page?: number;
limit?: number;
}
Expand Down
66 changes: 34 additions & 32 deletions src/search/data/get-pillar-items.ts
Original file line number Diff line number Diff line change
@@ -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<string[]> => {
// 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<string[]> => {
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<string[]> => {
// await new Promise((r) => setTimeout(r, 500));
// return fakePillarItems();
// };
2 changes: 2 additions & 0 deletions src/search/pages/pillar-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export const PillarPage = async ({ nav, params, searchParams }: Props) => {
params={params}
searchParams={searchParams}
pillarSlug={params.pillar}
pillarItems={mainItems}
activeItems={activeItems.include}
/>
}
Expand All @@ -92,6 +93,7 @@ export const PillarPage = async ({ nav, params, searchParams }: Props) => {
params={params}
searchParams={searchParams}
pillarSlug={slug}
pillarItems={items}
activeItems={activeItems[slug] || []}
/>
}
Expand Down
11 changes: 9 additions & 2 deletions src/search/utils/create-input-items.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -28,5 +32,8 @@ export const createInputItems = (
...altItemsArray,
];

return items;
return items.map((item) => ({
...item,
label: capitalize(denormalizeString(item.label)),
}));
};

0 comments on commit 3912736

Please sign in to comment.