diff --git a/.changeset/fluffy-pumpkins-drive.md b/.changeset/fluffy-pumpkins-drive.md index 2c805b3f..e7ae9422 100644 --- a/.changeset/fluffy-pumpkins-drive.md +++ b/.changeset/fluffy-pumpkins-drive.md @@ -2,4 +2,4 @@ "@namehash/namegraph-sdk": minor --- -Update NameGraph SDK to include new params in findCollectionsByString method +Update NameGraph SDK to include new API methods diff --git a/apps/namegraph.dev/app/collections/page.tsx b/apps/namegraph.dev/app/collections/page.tsx index 6e5ad8e4..bacb99ce 100644 --- a/apps/namegraph.dev/app/collections/page.tsx +++ b/apps/namegraph.dev/app/collections/page.tsx @@ -1,7 +1,10 @@ "use client"; /* eslint-disable react-hooks/exhaustive-deps */ -import { NameGraphCollection } from "@namehash/namegraph-sdk/utils"; +import { + NameGraphCollection, + NameGraphSortOrderOptions, +} from "@namehash/namegraph-sdk/utils"; import { findCollectionsByString } from "@/lib/utils"; import { DebounceInput } from "react-debounce-input"; import { Suspense, useEffect, useState } from "react"; @@ -29,24 +32,30 @@ interface NavigationConfig { } interface CollectionsData { + sort_order: NameGraphSortOrderOptions; other_collections: NameGraphCollection[]; related_collections: NameGraphCollection[]; } +const FromNameGraphSortOrderToDropdownTextContent: Record< + NameGraphSortOrderOptions, + string +> = { + [NameGraphSortOrderOptions.AI]: "AI with Learning to Rank", + [NameGraphSortOrderOptions.AZ]: "A-Z (asc)", + [NameGraphSortOrderOptions.ZA]: "Z-A (des)", + [NameGraphSortOrderOptions.ES]: "Default scoring", +}; + export default function ExploreCollectionsPage() { /** * Table query */ - enum ResultsOrderBy { - AiMatch = "AI match", - MostRecent = "Most recent", - MorePopular = "More popular", - } const DEFAULT_PAGE_NUMBER = 1; const DEFAULT_COLLECTIONS_PARAMS: Record<string, any> = { search: "", page: DEFAULT_PAGE_NUMBER, - orderBy: Object.keys(ResultsOrderBy)[0], + orderBy: NameGraphSortOrderOptions.AI, }; type DefaultDomainFiltersType = typeof DEFAULT_COLLECTIONS_PARAMS; const { params, setParams } = useQueryParams<DefaultDomainFiltersType>( @@ -60,7 +69,7 @@ export default function ExploreCollectionsPage() { }); }; - const handleOrderBy = (orderBy: string) => { + const handleOrderBy = (orderBy: NameGraphSortOrderOptions) => { setParams({ orderBy }); }; @@ -81,10 +90,6 @@ export default function ExploreCollectionsPage() { const [collectionsQueriedStandFor, setCollectionsQueriedStandFor] = useState(""); - useEffect(() => { - console.log(collections); - }, [collections]); - const [loadingCollections, setLoadingCollections] = useState(true); const DEFAULT_ITEMS_PER_PAGE = 20; @@ -106,9 +111,20 @@ export default function ExploreCollectionsPage() { /** * This is the case where we have already queried the results for * a given page, which is being visited once again and for which - * we have already stored its necessary data inside collections + * we have already stored its necessary data inside collections. + * + * There is no need then to re-do a load collections query. + * + * Of course this is only true if both the query and the sorting + * algorithm lastly used are the same. If any of these have changes, + * we do the loadCollections query once again and update the page's results. */ - if (collectionsQueriedStandFor && !!collections?.[params.page]) { + if ( + !!collectionsQueriedStandFor && + collectionsQueriedStandFor === params.search && + !!collections?.[params.page] && + params.orderBy == collections?.[params.page]?.sort_order + ) { return; } @@ -116,6 +132,7 @@ export default function ExploreCollectionsPage() { setCollectionsQueriedStandFor(query); findCollectionsByString(query, { offset: params.page - 1, + sort_order: params.orderBy, max_total_collections: MAX_RELATED_COLLECTIONS + OTHER_COLLECTIONS_NUMBER, /** @@ -153,13 +170,17 @@ export default function ExploreCollectionsPage() { setCollections({ ...collections, [params.page]: { + sort_order: params.orderBy, related_collections: relatedCollections, other_collections: moreCollections, }, }); setLoadingCollections(false); } else { - setCollections(undefined); + setCollections({ + ...collections, + [params.page]: null, + }); } }) .catch(() => { @@ -191,7 +212,7 @@ export default function ExploreCollectionsPage() { useEffect(() => { loadCollections(); - }, [params.page]); + }, [params.page, params.orderBy]); /** * Navigation helper functions @@ -297,24 +318,32 @@ export default function ExploreCollectionsPage() { Sort by </div> <Select - defaultValue={Object.keys(ResultsOrderBy)[0]} + defaultValue={ + params.orderBy || NameGraphSortOrderOptions.AI + } onValueChange={(newValue) => - handleOrderBy(newValue as ResultsOrderBy) + handleOrderBy( + newValue as NameGraphSortOrderOptions, + ) } > <SelectTrigger className="w-[180px]"> <SelectValue placeholder="Sort by" /> </SelectTrigger> <SelectContent> - {Object.entries(ResultsOrderBy).map( - ([key, value]) => { - return ( - <SelectItem key={key} value={key}> - {value} - </SelectItem> - ); - }, - )} + {Object.entries( + FromNameGraphSortOrderToDropdownTextContent, + ).map(([key]) => { + return ( + <SelectItem key={key} value={key}> + { + FromNameGraphSortOrderToDropdownTextContent[ + key as NameGraphSortOrderOptions + ] + } + </SelectItem> + ); + })} </SelectContent> </Select> </div> diff --git a/apps/namegraph.dev/components/collections/collections-grid-skeleton.tsx b/apps/namegraph.dev/components/collections/collections-grid-skeleton.tsx index 6b671cbd..104468af 100644 --- a/apps/namegraph.dev/components/collections/collections-grid-skeleton.tsx +++ b/apps/namegraph.dev/components/collections/collections-grid-skeleton.tsx @@ -35,16 +35,20 @@ export const CollectionsGridSkeleton = () => { ); }; +const NUMBER_OF_SKELETONS_OF_COLLECTION_CARDS = 5; + export const CollectionsCardsSkeleton = () => { return ( <> - {[...Array(5).keys()].map((collection) => { - return ( - <div key={collection}> - <CollectionCardSkeleton /> - </div> - ); - })} + {[...Array(NUMBER_OF_SKELETONS_OF_COLLECTION_CARDS).keys()].map( + (collection) => { + return ( + <div key={collection}> + <CollectionCardSkeleton /> + </div> + ); + }, + )} </> ); }; diff --git a/apps/namegraph.dev/lib/utils.ts b/apps/namegraph.dev/lib/utils.ts index 1b4e2db4..8fa3126d 100644 --- a/apps/namegraph.dev/lib/utils.ts +++ b/apps/namegraph.dev/lib/utils.ts @@ -6,6 +6,7 @@ import { NameGraphFindCollectionsResponse, NameGraphGroupedByCategoryResponse, NameGraphGroupingCategory, + NameGraphSortOrderOptions, NameGraphSuggestion, } from "@namehash/namegraph-sdk/utils"; import { createNameGraphClient } from "@namehash/namegraph-sdk"; @@ -119,6 +120,7 @@ export const findCollectionsByString = async ( max_other_collections?: number; max_total_collections?: number; max_related_collections?: number; + sort_order?: NameGraphSortOrderOptions; }, ): Promise<NameGraphFindCollectionsResponse> => { let query = input; diff --git a/apps/namegraph.dev/next.config.mjs b/apps/namegraph.dev/next.config.mjs index e1791def..cbed5e1b 100644 --- a/apps/namegraph.dev/next.config.mjs +++ b/apps/namegraph.dev/next.config.mjs @@ -1,6 +1,26 @@ /** @type {import('next').NextConfig} */ const nextConfig = { experimental: { + /** + * The Suspense boundary is necessary as per: + * + * We are disabling this need as this would turn the usage + * of search params very much difficult in our application. + * + * We do this disabling then, basically to be able to use + * "useSearchParams" without the Suspense boundary which is not + * harmful for our use case. + * + * There is no risk on disabling this and this can be understood by understanding: + * 1. Next.js itself allows it; + * 2. "Reading search parameters through useSearchParams() without + * a Suspense boundary will opt the entire page into client-side rendering" + * which is not really a problem for our use case; + * + * For diving deeper on this, please refer to: + * + * https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout#why-this-error-occurred + */ missingSuspenseWithCSRBailout: false, } }; diff --git a/packages/namegraph-sdk/src/index.ts b/packages/namegraph-sdk/src/index.ts index eb557868..0e59e9cd 100644 --- a/packages/namegraph-sdk/src/index.ts +++ b/packages/namegraph-sdk/src/index.ts @@ -19,6 +19,7 @@ import { DEFAULT_NAME_DIVERSITY_RATIO, DEFAULT_MAX_PER_TYPE, DEFAULT_INSTANT_MODE, + NameGraphSortOrderOptions, } from "./utils"; export class NameGraph { @@ -168,13 +169,14 @@ export class NameGraph { max_other_collections?: number; max_related_collections?: number; max_total_collections?: number; + sort_order?: NameGraphSortOrderOptions; }, ): Promise<NameGraphFindCollectionsResponse> { const offset = options?.offset || 0; const mode = "instant"; const limit_names = 10; const max_per_type = 3; - const sort_order = "AI"; + const sort_order = options?.sort_order || NameGraphSortOrderOptions.AI; const min_other_collections = options?.min_other_collections || 0; const max_other_collections = options?.max_other_collections || 3; const max_total_collections = options?.max_total_collections || 6; diff --git a/packages/namegraph-sdk/src/utils.ts b/packages/namegraph-sdk/src/utils.ts index 76eb81b0..251232da 100644 --- a/packages/namegraph-sdk/src/utils.ts +++ b/packages/namegraph-sdk/src/utils.ts @@ -167,6 +167,14 @@ export const DEFAULT_INSTANT_MODE = "instant"; export const DEFAULT_ENABLE_LEARNING_TO_RANK = true; export const DEFAULT_NAME_DIVERSITY_RATIO = 0.5; export const DEFAULT_MAX_PER_TYPE = 2; +export const NameGraphSortOrderOptions = { + AI: "AI", + AZ: "A-Z", + ZA: "Z-A", + ES: "ES", +} as const; +export type NameGraphSortOrderOptions = + (typeof NameGraphSortOrderOptions)[keyof typeof NameGraphSortOrderOptions]; /** * Writers block suggestions and collections