Skip to content

Commit

Permalink
refactor: move and rename fetchers, options
Browse files Browse the repository at this point in the history
  • Loading branch information
dominik-stumpf committed Dec 4, 2024
1 parent a832ed5 commit 038ffc8
Show file tree
Hide file tree
Showing 14 changed files with 108 additions and 55 deletions.
21 changes: 0 additions & 21 deletions src/actions/token.ts
Original file line number Diff line number Diff line change
@@ -1,21 +0,0 @@
import { getTokenClientSide } from "@/lib/getCookieClientSide";
import { tokenSchema } from "@/lib/schemas/user";
import { isServer } from "@tanstack/react-query";
import { jwtDecode } from "jwt-decode";
import { getTokenServerSide } from "./auth";

export const tryGetToken = async () => {
const token = isServer ? await getTokenServerSide() : getTokenClientSide();

if (!token) {
throw new Error(
"Failed to retrieve JWT token on auth request initialization.",
);
}
return token;
};

export const tryGetParsedToken = async () => {
const token = await tryGetToken();
return tokenSchema.parse(jwtDecode(token));
};
23 changes: 9 additions & 14 deletions src/app/(dashboard)/[guildUrlName]/actions.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
import { tryGetParsedToken } from "@/actions/token";
import { fetchGuildApiData } from "@/lib/fetchGuildApi";
import { resolveIdLikeRequest } from "@/lib/resolveIdLikeRequest";
import { tryGetParsedToken } from "@/lib/token";
import type { ErrorLike, WithIdLike } from "@/lib/types";
import type { Schemas } from "@guildxyz/types";
import z from "zod";

const resolveIdLikeRequest = (idLike: string) => {
const isId = z.string().uuid().safeParse(idLike).success;
return `${isId ? "id" : "urlName"}/${idLike}`;
};

export const leaveGuild = async ({ guildId }: { guildId: string }) => {
export const fetchGuildLeave = async ({ guildId }: { guildId: string }) => {
return fetchGuildApiData(`guild/${guildId}/leave`, {
method: "POST",
});
};

export const getGuild = async ({ idLike }: WithIdLike) => {
export const fetchGuild = async ({ idLike }: WithIdLike) => {
return fetchGuildApiData<Schemas["GuildFull"]>(
`guild/${resolveIdLikeRequest(idLike)}`,
);
};

export const getEntity = async <Data = object, Error = ErrorLike>({
export const fetchEntity = async <Data = object, Error = ErrorLike>({
idLike,
entity,
responseInit,
Expand All @@ -34,16 +29,16 @@ export const getEntity = async <Data = object, Error = ErrorLike>({
return fetchGuildApiData<Data, Error>(pathname, responseInit);
};

export const getUser = async () => {
export const fetchUser = async () => {
const { userId } = await tryGetParsedToken();
return getEntity<Schemas["UserFull"]>({
return fetchEntity<Schemas["UserFull"]>({
entity: "user",
idLike: userId,
});
};

export const getPages = async ({ guildId }: { guildId: string }) => {
const guild = await getGuild({ idLike: guildId });
export const fetchPages = async ({ guildId }: { guildId: string }) => {
const guild = await fetchGuild({ idLike: guildId });
return fetchGuildApiData<Schemas["PageFull"][]>("page/batch", {
method: "POST",
body: JSON.stringify({ ids: guild.pages?.map((p) => p.pageId!) ?? [] }),

Check warning on line 44 in src/app/(dashboard)/[guildUrlName]/actions.ts

View workflow job for this annotation

GitHub Actions / quality-assurance

lint/style/noNonNullAssertion

Forbidden non-null assertion.
Expand Down
4 changes: 2 additions & 2 deletions src/app/(dashboard)/[guildUrlName]/components/GuildTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { Card } from "@/components/ui/Card";
import { ScrollArea, ScrollBar } from "@/components/ui/ScrollArea";
import { Skeleton } from "@/components/ui/Skeleton";
import { cn } from "@/lib/cssUtils";
import { fetchPages } from "@/lib/fetchers";
import type { Schemas } from "@guildxyz/types";
import { getPages } from "../actions";
import { PageNavLink } from "./RoleGroupNavLink";

export const GuildTabs = async ({ guild }: { guild: Schemas["GuildFull"] }) => {
const pages = await getPages({ guildId: guild.id });
const pages = await fetchPages({ guildId: guild.id });

return (
<ScrollArea
Expand Down
6 changes: 3 additions & 3 deletions src/app/(dashboard)/[guildUrlName]/components/JoinButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { Button } from "@/components/ui/Button";
import { GUILD_AUTH_COOKIE_NAME } from "@/config/constants";
import { env } from "@/lib/env";
import { getCookieClientSide } from "@/lib/getCookieClientSide";
import { guildOptions, userOptions } from "@/lib/options";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { EventSourcePlus } from "event-source-plus";
import { useParams } from "next/navigation";
import { toast } from "sonner";
import { leaveGuild } from "../actions";
import { guildOptions, userOptions } from "../options";
import { fetchGuildLeave } from "../actions";

export const JoinButton = () => {
const { guildUrlName } = useParams<{ guildUrlName: string }>();
Expand Down Expand Up @@ -73,7 +73,7 @@ export const JoinButton = () => {
});

const leaveMutation = useMutation({
mutationFn: () => leaveGuild({ guildId: guild.data.id }),
mutationFn: () => fetchGuildLeave({ guildId: guild.data.id }),
onSuccess: async () => {
await queryClient.cancelQueries(userOptions());
const prev = queryClient.getQueryData(userOptions().queryKey);
Expand Down
2 changes: 1 addition & 1 deletion src/app/(dashboard)/[guildUrlName]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { AuthBoundary } from "@/components/AuthBoundary";
import { GuildImage } from "@/components/GuildImage";
import { SignInButton } from "@/components/SignInButton";
import { getQueryClient } from "@/lib/getQueryClient";
import { guildOptions, userOptions } from "@/lib/options";
import type { DynamicRoute } from "@/lib/types";
import { HydrationBoundary, dehydrate } from "@tanstack/react-query";
import { type PropsWithChildren, Suspense } from "react";
import { GuildTabs, GuildTabsSkeleton } from "./components/GuildTabs";
import { JoinButton } from "./components/JoinButton";
import { guildOptions, userOptions } from "./options";

const GuildLayout = async ({
params,
Expand Down
5 changes: 2 additions & 3 deletions src/app/(dashboard)/explorer/actions.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
"use server";
import { fetchGuildApiData } from "@/lib/fetchGuildApi";
import type { Guild } from "@/lib/schemas/guild";
import type { PaginatedResponse } from "@/lib/types";
import type { Schemas } from "@guildxyz/types";
import { PAGE_SIZE } from "./constants";

export const getGuildSearch = async ({
pageParam,
search,
}: { pageParam: number; search: string }) => {
return fetchGuildApiData<PaginatedResponse<Guild>>(
return fetchGuildApiData<PaginatedResponse<Schemas["GuildFull"]>>(
`guild/search?page=${pageParam}&pageSize=${PAGE_SIZE}&search=${search}`,
);
};
6 changes: 4 additions & 2 deletions src/app/(dashboard)/explorer/components/GuildCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { GuildImage } from "@/components/GuildImage";
import { Badge } from "@/components/ui/Badge";
import { Card } from "@/components/ui/Card";
import { Skeleton } from "@/components/ui/Skeleton";
import type { Guild } from "@/lib/schemas/guild";
import type { Schemas } from "@guildxyz/types";
import { Users } from "@phosphor-icons/react/dist/ssr";

import Link from "next/link";
import type { FunctionComponent } from "react";

export const GuildCard: FunctionComponent<{ guild: Guild }> = ({ guild }) => {
export const GuildCard: FunctionComponent<{ guild: Schemas["GuildFull"] }> = ({
guild,
}) => {
return (
<Link
href={`/${guild.urlName}`}
Expand Down
13 changes: 9 additions & 4 deletions src/app/(dashboard)/explorer/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { tryGetParsedToken } from "@/actions/token";
import { AuthBoundary } from "@/components/AuthBoundary";
import { SignInButton } from "@/components/SignInButton";
import { fetchGuildApiData } from "@/lib/fetchGuildApi";
import { getQueryClient } from "@/lib/getQueryClient";
import type { Guild } from "@/lib/schemas/guild";
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";
Expand All @@ -19,7 +19,7 @@ import { ACTIVE_SECTION } from "./constants";
const getAssociatedGuilds = async () => {
const { userId } = await tryGetParsedToken();

return fetchGuildApiData<PaginatedResponse<Guild>>(
return fetchGuildApiData<PaginatedResponse<Schemas["GuildFull"]>>(
`guild/search?page=1&pageSize=${Number.MAX_SAFE_INTEGER}&sortBy=name&reverse=false&customQuery=@owner:{${userId}}`,
);
};
Expand Down Expand Up @@ -108,7 +108,12 @@ async function AssociatedGuildsSection() {
}

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

return associatedGuilds.length > 0 ? (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
Expand Down
2 changes: 1 addition & 1 deletion src/lib/fetchGuildApi.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { tryGetToken } from "@/actions/token";
import { tryGetToken } from "@/lib/token";
import { env } from "./env";
import type { ErrorLike } from "./types";

Expand Down
46 changes: 46 additions & 0 deletions src/lib/fetchers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { fetchGuildApiData } from "@/lib/fetchGuildApi";
import { resolveIdLikeRequest } from "@/lib/resolveIdLikeRequest";
import { tryGetParsedToken } from "@/lib/token";
import type { ErrorLike, WithIdLike } from "@/lib/types";
import type { Schemas } from "@guildxyz/types";

export const fetchGuildLeave = async ({ guildId }: { guildId: string }) => {
return fetchGuildApiData(`guild/${guildId}/leave`, {
method: "POST",
});
};

export const fetchGuild = async ({ idLike }: WithIdLike) => {
return fetchGuildApiData<Schemas["GuildFull"]>(
`guild/${resolveIdLikeRequest(idLike)}`,
);
};

export const fetchEntity = async <Data = object, Error = ErrorLike>({
idLike,
entity,
responseInit,
}: {
entity: string;
idLike: string;
responseInit?: Parameters<typeof fetch>[1];
}) => {
const pathname = `${entity}/${resolveIdLikeRequest(idLike)}`;
return fetchGuildApiData<Data, Error>(pathname, responseInit);
};

export const fetchUser = async () => {
const { userId } = await tryGetParsedToken();
return fetchEntity<Schemas["UserFull"]>({
entity: "user",
idLike: userId,
});
};

export const fetchPages = async ({ guildId }: { guildId: string }) => {
const guild = await fetchGuild({ idLike: guildId });
return fetchGuildApiData<Schemas["PageFull"][]>("page/batch", {
method: "POST",
body: JSON.stringify({ ids: guild.pages?.map((p) => p.pageId!) ?? [] }),

Check warning on line 44 in src/lib/fetchers.ts

View workflow job for this annotation

GitHub Actions / quality-assurance

lint/style/noNonNullAssertion

Forbidden non-null assertion.
});
};
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { fetchEntity, fetchUser } from "@/lib/fetchers";
import type { ErrorLike } from "@/lib/types";
import type { Schemas } from "@guildxyz/types";
import { queryOptions } from "@tanstack/react-query";
import { getEntity, getUser } from "./actions";

export const entityOptions = <Data = object, Error = ErrorLike>({
entity,
idLike,
...rest
}: Parameters<typeof getEntity>[0]) => {
}: Parameters<typeof fetchEntity>[0]) => {
return queryOptions<Data, Error>({
queryKey: [entity, idLike],
queryFn: () => getEntity({ entity, idLike, ...rest }),
queryFn: () => fetchEntity({ entity, idLike, ...rest }),
});
};

Expand All @@ -24,6 +24,6 @@ export const guildOptions = ({ idLike }: { idLike: string }) => {
export const userOptions = () => {
return queryOptions<Schemas["UserFull"]>({
queryKey: ["user"],
queryFn: () => getUser(),
queryFn: () => fetchUser(),
});
};
6 changes: 6 additions & 0 deletions src/lib/resolveIdLikeRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import z from "zod";

export const resolveIdLikeRequest = (idLike: string) => {
const isId = z.string().uuid().safeParse(idLike).success;
return `${isId ? "id" : "urlName"}/${idLike}`;
};
21 changes: 21 additions & 0 deletions src/lib/token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { getTokenServerSide } from "@/actions/auth";
import { getTokenClientSide } from "@/lib/getCookieClientSide";
import { tokenSchema } from "@/lib/schemas/user";
import { isServer } from "@tanstack/react-query";
import { jwtDecode } from "jwt-decode";

export const tryGetToken = async () => {
const token = isServer ? await getTokenServerSide() : getTokenClientSide();

if (!token) {
throw new Error(
"Failed to retrieve JWT token on auth request initialization.",
);
}
return token;
};

export const tryGetParsedToken = async () => {
const token = await tryGetToken();
return tokenSchema.parse(jwtDecode(token));
};
Empty file added src/v2/components/ui/Button.tsx
Empty file.

0 comments on commit 038ffc8

Please sign in to comment.