Skip to content

Commit

Permalink
refactor: use tanstack query on explorer
Browse files Browse the repository at this point in the history
  • Loading branch information
dominik-stumpf committed Dec 4, 2024
1 parent b216960 commit b5bf336
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 127 deletions.
13 changes: 0 additions & 13 deletions src/app/(dashboard)/explorer/actions.ts

This file was deleted.

40 changes: 40 additions & 0 deletions src/app/(dashboard)/explorer/components/AssociatedGuilds.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"use client";

import { useSuspenseQuery } from "@tanstack/react-query";
import { associatedGuildsOption } from "../options";
import { CreateGuildLink } from "./CreateGuildLink";
import { GuildCard, GuildCardSkeleton } from "./GuildCard";

export const AssociatedGuilds = () => {
const { data: associatedGuilds } = useSuspenseQuery(associatedGuildsOption());

return associatedGuilds.length > 0 ? (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{associatedGuilds.map((guild) => (
<GuildCard key={guild.id} guild={guild} />
))}
</div>
) : (
<div className="flex items-center gap-4 rounded-2xl bg-card px-5 py-6">
<img src="/images/robot.svg" alt="Guild Robot" className="size-8" />

<p className="font-semibold">
You&apos;re not a member of any guilds yet. Explore and join some below,
or create your own!
</p>

<CreateGuildLink className="ml-auto" />
</div>
);
};

export const AssociatedGuildsSkeleton = () => {
return (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{Array.from({ length: 3 }, (_, i) => (
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
<GuildCardSkeleton key={i} />
))}
</div>
);
};
15 changes: 2 additions & 13 deletions src/app/(dashboard)/explorer/components/InfiniteScrollGuilds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,15 @@ import { useInfiniteQuery } from "@tanstack/react-query";
import { useIntersection } from "foxact/use-intersection";
import { useAtomValue } from "jotai";
import { useCallback, useEffect } from "react";
import { getGuildSearch } from "../actions";
import { searchAtom } from "../atoms";
import { PAGE_SIZE } from "../constants";
import { guildSearchOptions } from "../options";
import { GuildCard, GuildCardSkeleton } from "./GuildCard";

export const InfiniteScrollGuilds = () => {
const search = useAtomValue(searchAtom);
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading } =
useInfiniteQuery({
queryKey: ["guilds", search || ""],
queryFn: ({ pageParam }) =>
getGuildSearch({ search: search || "", pageParam }),
initialPageParam: 1,
staleTime: Number.POSITIVE_INFINITY,
enabled: search !== undefined,
getNextPageParam: (lastPage) =>
lastPage.total / lastPage.pageSize <= lastPage.page
? undefined
: lastPage.page + 1,
});
useInfiniteQuery(guildSearchOptions({ search }));

const [setIntersection, isIntersected, resetIsIntersected] = useIntersection({
rootMargin: "700px",
Expand Down
28 changes: 18 additions & 10 deletions src/app/(dashboard)/explorer/fetchers.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import { env } from "@/lib/env";
import type { Guild } from "@/lib/schemas/guild";
import { fetchGuildApiData } from "@/lib/fetchGuildApi";
import { tryGetParsedToken } from "@/lib/token";
import type { PaginatedResponse } from "@/lib/types";
import { fetcher } from "../../../lib/fetcher";
import type { Schemas } from "@guildxyz/types";
import { PAGE_SIZE } from "./constants";

export const getGuildSearch =
(search = "") =>
async ({ pageParam }: { pageParam: number }) => {
return fetcher<PaginatedResponse<Guild>>(
`${env.NEXT_PUBLIC_API}/guild/search?page=${pageParam}&pageSize=${PAGE_SIZE}&search=${search}`,
);
};
export const fetchAssociatedGuilds = async () => {
const { userId } = await tryGetParsedToken();
return fetchGuildApiData<PaginatedResponse<Schemas["Guild"]>>(
`guild/search?page=1&pageSize=${Number.MAX_SAFE_INTEGER}&sortBy=name&reverse=false&customQuery=@owner:{${userId}}`,
);
};

export const fetchGuildSearch = async ({
pageParam,
search,
}: { pageParam: number; search: string }) => {
return fetchGuildApiData<PaginatedResponse<Schemas["Guild"]>>(
`guild/search?page=${pageParam}&pageSize=${PAGE_SIZE}&search=${search}`,
);
};
21 changes: 21 additions & 0 deletions src/app/(dashboard)/explorer/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { getQueryClient } from "@/lib/getQueryClient";
import { HydrationBoundary, dehydrate } from "@tanstack/react-query";
import type { PropsWithChildren } from "react";
import { associatedGuildsOption, guildSearchOptions } from "./options";

const ExplorerLayout = async ({ children }: PropsWithChildren) => {
const queryClient = getQueryClient();
void queryClient.prefetchInfiniteQuery(
guildSearchOptions({}),
//queryFn: () => fetchGuildSearch({ search: "", pageParam: 1 }),
);
void queryClient.prefetchQuery(associatedGuildsOption());

return (
<HydrationBoundary state={dehydrate(queryClient)}>
{children}
</HydrationBoundary>
);
};

export default ExplorerLayout;
23 changes: 23 additions & 0 deletions src/app/(dashboard)/explorer/options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { infiniteQueryOptions, queryOptions } from "@tanstack/react-query";
import { fetchAssociatedGuilds, fetchGuildSearch } from "./fetchers";

export const associatedGuildsOption = () => {
return queryOptions({
queryKey: ["associatedGuilds"],
queryFn: () => fetchAssociatedGuilds(),
select: (data) => data.items,
});
};

export const guildSearchOptions = ({ search = "" }: { search?: string }) => {
return infiniteQueryOptions({
queryKey: ["guilds", search],
queryFn: ({ pageParam }) => fetchGuildSearch({ search: search, pageParam }),
initialPageParam: 1,
enabled: search !== undefined,
getNextPageParam: (lastPage) =>
lastPage.total / lastPage.pageSize <= lastPage.page
? undefined
: lastPage.page + 1,
});
};
74 changes: 8 additions & 66 deletions src/app/(dashboard)/explorer/page.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,18 @@
import { AuthBoundary } from "@/components/AuthBoundary";
import { SignInButton } from "@/components/SignInButton";
import { fetchGuildApiData } from "@/lib/fetchGuildApi";
import { getQueryClient } from "@/lib/getQueryClient";
import { tryGetParsedToken } from "@/lib/token";
import type { PaginatedResponse } from "@/lib/types";
import type { Schemas } from "@guildxyz/types";
import { HydrationBoundary, dehydrate } from "@tanstack/react-query";
import { Suspense } from "react";
import { getGuildSearch } from "./actions";
import {
AssociatedGuilds,
AssociatedGuildsSkeleton,
} from "./components/AssociatedGuilds";
import { CreateGuildLink } from "./components/CreateGuildLink";
import { GuildCard, GuildCardSkeleton } from "./components/GuildCard";
import { HeaderBackground } from "./components/HeaderBackground";
import { InfiniteScrollGuilds } from "./components/InfiniteScrollGuilds";
import { StickyNavbar } from "./components/StickyNavbar";
import { StickySearch } from "./components/StickySearch";
import { ACTIVE_SECTION } from "./constants";

const getAssociatedGuilds = async () => {
const { userId } = await tryGetParsedToken();

return fetchGuildApiData<PaginatedResponse<Schemas["Guild"]>>(
`guild/search?page=1&pageSize=${Number.MAX_SAFE_INTEGER}&sortBy=name&reverse=false&customQuery=@owner:{${userId}}`,
);
};

export default async function Explorer() {
const queryClient = getQueryClient();
await queryClient.prefetchInfiniteQuery({
queryKey: ["guilds", ""],
initialPageParam: 1,
queryFn: () => getGuildSearch({ search: "", pageParam: 1 }),
});

const Explorer = async () => {
return (
<>
<div
Expand Down Expand Up @@ -69,13 +50,11 @@ export default async function Explorer() {
</h2>
<StickySearch />

<HydrationBoundary state={dehydrate(queryClient)}>
<InfiniteScrollGuilds />
</HydrationBoundary>
<InfiniteScrollGuilds />
</main>
</>
);
}
};

async function AssociatedGuildsSection() {
return (
Expand Down Expand Up @@ -107,41 +86,4 @@ async function AssociatedGuildsSection() {
);
}

async function AssociatedGuilds() {
let associatedGuilds: Schemas["Guild"][];
try {
associatedGuilds = (await getAssociatedGuilds()).items;
} catch {
return;
}

return associatedGuilds.length > 0 ? (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{associatedGuilds.map((guild) => (
<GuildCard key={guild.id} guild={guild} />
))}
</div>
) : (
<div className="flex items-center gap-4 rounded-2xl bg-card px-5 py-6">
<img src="/images/robot.svg" alt="Guild Robot" className="size-8" />

<p className="font-semibold">
You&apos;re not a member of any guilds yet. Explore and join some below,
or create your own!
</p>

<CreateGuildLink className="ml-auto" />
</div>
);
}

function AssociatedGuildsSkeleton() {
return (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{Array.from({ length: 3 }, (_, i) => (
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
<GuildCardSkeleton key={i} />
))}
</div>
);
}
export default Explorer;
25 changes: 0 additions & 25 deletions src/lib/fetcher.ts

This file was deleted.

0 comments on commit b5bf336

Please sign in to comment.