diff --git a/apps/dashboard/app/(app)/apis/_components/api-list-client.tsx b/apps/dashboard/app/(app)/apis/_components/api-list-client.tsx index 7e460b88ec..2256810f9d 100644 --- a/apps/dashboard/app/(app)/apis/_components/api-list-client.tsx +++ b/apps/dashboard/app/(app)/apis/_components/api-list-client.tsx @@ -1,58 +1,130 @@ "use client"; import { EmptyComponentSpacer } from "@/components/empty-component-spacer"; -import type { - ApiOverview, - ApisOverviewResponse, -} from "@/lib/trpc/routers/api/overview/query-overview/schemas"; +import { trpc } from "@/lib/trpc/client"; import { BookBookmark } from "@unkey/icons"; import { Button, Empty } from "@unkey/ui"; -import { useState } from "react"; -import { ApiListGrid } from "./api-list-grid"; +import { useRouter, useSearchParams } from "next/navigation"; +import { useEffect, useMemo, useState } from "react"; +import { ApiListCard } from "./api-list-card"; import { ApiListControlCloud } from "./control-cloud"; import { ApiListControls } from "./controls"; import { CreateApiButton } from "./create-api-button"; +import { ApiCardSkeleton } from "./skeleton"; -export const ApiListClient = ({ - initialData, -}: { - initialData: ApisOverviewResponse; -}) => { - const [isSearching, setIsSearching] = useState(false); - const [apiList, setApiList] = useState(initialData.apiList); +const DEFAULT_LIMIT = 10; + +export const ApiListClient = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + const isNewApi = searchParams?.get("new") === "true"; + + const { + data: apisData, + isLoading, + error, + fetchNextPage, + hasNextPage, + isFetchingNextPage, + } = trpc.api.overview.query.useInfiniteQuery( + { limit: DEFAULT_LIMIT }, + { + getNextPageParam: (lastPage) => lastPage.nextCursor, + }, + ); + + const allApis = useMemo(() => { + if (!apisData?.pages) { + return []; + } + return apisData.pages.flatMap((page) => page.apiList); + }, [apisData]); + + const [apiList, setApiList] = useState(allApis); + const [isSearching, setIsSearching] = useState(false); + + useEffect(() => { + setApiList(allApis); + }, [allApis]); + + useEffect(() => { + if (error) { + router.push("/new"); + } + }, [error, router]); + + const loadMore = () => { + if (hasNextPage && !isFetchingNextPage) { + fetchNextPage(); + } + }; return (
- + - {initialData.apiList.length > 0 ? ( - + + {isLoading ? ( +
+ {Array.from({ length: DEFAULT_LIMIT }).map((_, i) => ( + // biome-ignore lint/suspicious/noArrayIndexKey: It's okay to use index + + ))} +
+ ) : apiList.length > 0 ? ( + <> +
+ {apiList.map((api) => ( + + ))} +
+ +
+
+ Showing {apiList.length} of {apisData?.pages[0]?.total || 0} APIs +
+ + {!isSearching && hasNextPage && ( + + )} +
+ ) : ( No APIs found - You haven't created any APIs yet. Create one to get started. + {isSearching + ? "No APIs match your search criteria. Try a different search term." + : "You haven't created any APIs yet. Create one to get started."} - - - - - - + {!isSearching && ( + + + + + + + )} )} diff --git a/apps/dashboard/app/(app)/apis/_components/api-list-grid.tsx b/apps/dashboard/app/(app)/apis/_components/api-list-grid.tsx index 40b0aeda2e..bc77345e80 100644 --- a/apps/dashboard/app/(app)/apis/_components/api-list-grid.tsx +++ b/apps/dashboard/app/(app)/apis/_components/api-list-grid.tsx @@ -1,28 +1,24 @@ import { EmptyComponentSpacer } from "@/components/empty-component-spacer"; - -import type { - ApiOverview, - ApisOverviewResponse, -} from "@/lib/trpc/routers/api/overview/query-overview/schemas"; +import type { ApiOverview } from "@/lib/trpc/routers/api/overview/query-overview/schemas"; import { ChevronDown } from "@unkey/icons"; import { Button, Empty } from "@unkey/ui"; -import type { Dispatch, SetStateAction } from "react"; import { ApiListCard } from "./api-list-card"; -import { useFetchApiOverview } from "./hooks/use-fetch-api-overview"; export const ApiListGrid = ({ - initialData, - setApiList, apiList, isSearching, + onLoadMore, + hasMore, + isLoadingMore, + total, }: { - initialData: ApisOverviewResponse; apiList: ApiOverview[]; - setApiList: Dispatch>; isSearching?: boolean; + onLoadMore: () => void; + hasMore: boolean; + isLoadingMore: boolean; + total: number; }) => { - const { total, loadMore, isLoading, hasMore } = useFetchApiOverview(initialData, setApiList); - if (apiList.length === 0) { return ( @@ -44,13 +40,15 @@ export const ApiListGrid = ({ ))}
+
Showing {apiList.length} of {total} APIs
+ {!isSearching && hasMore && ( -