From 9cdf9c1d9620aceb393b2089655398d2530eb980 Mon Sep 17 00:00:00 2001 From: FrancoAguzzi Date: Fri, 10 Jan 2025 17:29:31 -0300 Subject: [PATCH] =?UTF-8?q?feat:=20[SC-26092]=20=E2=9C=A8=20Update=20sort?= =?UTF-8?q?=20options=20in=20namegraph.dev=20and=20namegraph-sdk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/fluffy-pumpkins-drive.md | 2 +- apps/namegraph.dev/app/collections/page.tsx | 83 +++++++++++++------ .../collections/collections-grid-skeleton.tsx | 18 ++-- apps/namegraph.dev/lib/utils.ts | 2 + apps/namegraph.dev/next.config.mjs | 20 +++++ packages/namegraph-sdk/src/index.ts | 4 +- packages/namegraph-sdk/src/utils.ts | 8 ++ 7 files changed, 101 insertions(+), 36 deletions(-) diff --git a/.changeset/fluffy-pumpkins-drive.md b/.changeset/fluffy-pumpkins-drive.md index 2c805b3f8..e7ae9422a 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 6e5ad8e48..bacb99ce5 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 = { search: "", page: DEFAULT_PAGE_NUMBER, - orderBy: Object.keys(ResultsOrderBy)[0], + orderBy: NameGraphSortOrderOptions.AI, }; type DefaultDomainFiltersType = typeof DEFAULT_COLLECTIONS_PARAMS; const { params, setParams } = useQueryParams( @@ -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 diff --git a/apps/namegraph.dev/components/collections/collections-grid-skeleton.tsx b/apps/namegraph.dev/components/collections/collections-grid-skeleton.tsx index 6b671cbd6..104468af3 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 ( -
- -
- ); - })} + {[...Array(NUMBER_OF_SKELETONS_OF_COLLECTION_CARDS).keys()].map( + (collection) => { + return ( +
+ +
+ ); + }, + )} ); }; diff --git a/apps/namegraph.dev/lib/utils.ts b/apps/namegraph.dev/lib/utils.ts index 1b4e2db42..8fa3126da 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 => { let query = input; diff --git a/apps/namegraph.dev/next.config.mjs b/apps/namegraph.dev/next.config.mjs index e1791def6..cbed5e1bf 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 eb557868d..0e59e9cdd 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 { 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 76eb81b0b..251232da7 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