From 393e5c7fa66cbc756f22685166b1cabdb0fd92f5 Mon Sep 17 00:00:00 2001 From: Adrian <107351903+6lr61@users.noreply.github.com> Date: Wed, 18 Sep 2024 08:54:02 +0200 Subject: [PATCH] refactor: use useQuery instead of context --- src/components/BadgeList.tsx | 7 ++- src/components/Chat.tsx | 13 ++--- src/components/Message.tsx | 4 +- src/contexts/badges/TwitchBadgeContext.ts | 10 ---- src/contexts/badges/TwitchBadgeProvider.tsx | 54 --------------------- src/hooks/useBadges.ts | 30 ++++++++++++ src/utils/api/getBadges.ts | 13 +++-- 7 files changed, 49 insertions(+), 82 deletions(-) delete mode 100644 src/contexts/badges/TwitchBadgeContext.ts delete mode 100644 src/contexts/badges/TwitchBadgeProvider.tsx create mode 100644 src/hooks/useBadges.ts diff --git a/src/components/BadgeList.tsx b/src/components/BadgeList.tsx index e917032..b4ded3a 100644 --- a/src/components/BadgeList.tsx +++ b/src/components/BadgeList.tsx @@ -1,5 +1,4 @@ -import { useContext } from "react"; -import { TwitchBadgeConext } from "../contexts/badges/TwitchBadgeContext"; +import { useBadges } from "../hooks/useBadges"; interface Props { // FIXME: Derive this from a single point of truth @@ -18,7 +17,7 @@ function makeKey(setId: string, id: string): `${string}/${string}` { export default function BadgeList({ badges, }: Props): React.ReactElement | undefined { - const twitchBadges = useContext(TwitchBadgeConext); + const twitchBadges = useBadges(); if (badges.length === 0) { return; @@ -29,7 +28,7 @@ export default function BadgeList({ {badges.map(({ set_id, id }) => ( ))} diff --git a/src/components/Chat.tsx b/src/components/Chat.tsx index 837cb29..c89c4be 100644 --- a/src/components/Chat.tsx +++ b/src/components/Chat.tsx @@ -1,5 +1,4 @@ import { useEffect, useRef } from "react"; -import TwitchBadgeProvider from "../contexts/badges/TwitchBadgeProvider"; import { useTwitchChat } from "../hooks/useTwitchChat"; import Message from "./Message"; @@ -17,13 +16,11 @@ export default function Chat(): React.ReactElement { return (
- -
- {messages.map((message) => ( - - ))} -
-
+
+ {messages.map((message) => ( + + ))} +
); } diff --git a/src/components/Message.tsx b/src/components/Message.tsx index 30bb82a..7da9a57 100644 --- a/src/components/Message.tsx +++ b/src/components/Message.tsx @@ -55,8 +55,8 @@ export default function Message({ message }: Props): React.ReactElement { style={{ backgroundColor: colorToRgba(message.color) }} > - - + + {message.reply && } diff --git a/src/contexts/badges/TwitchBadgeContext.ts b/src/contexts/badges/TwitchBadgeContext.ts deleted file mode 100644 index ccb6914..0000000 --- a/src/contexts/badges/TwitchBadgeContext.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createContext } from "react"; -import type { Badge, BadgeSet } from "../../utils/api/getBadges"; - -export type BadgeKey = `${BadgeSet["set_id"]}/${Badge["id"]}`; -export type BadgeValue = Omit; -export type TwitchBadges = Map; - -export const TwitchBadgeConext = createContext( - new Map() -); diff --git a/src/contexts/badges/TwitchBadgeProvider.tsx b/src/contexts/badges/TwitchBadgeProvider.tsx deleted file mode 100644 index b537ead..0000000 --- a/src/contexts/badges/TwitchBadgeProvider.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { useContext, useEffect, useState } from "react"; -import { - TwitchBadgeConext, - type BadgeKey, - type BadgeValue, - type TwitchBadges, -} from "./TwitchBadgeContext"; -import { AuthContext } from "../auth-state/AuthContext"; -import { getBadges } from "../../utils/api/getBadges"; - -interface Props { - children: React.ReactNode; -} - -export default function TwitchBadgeProvider({ - children, -}: Props): React.ReactElement { - const [badges, setBadges] = useState( - () => new Map() - ); - const { authState } = useContext(AuthContext); - - useEffect(() => { - let keep = true; - - if (!authState) { - return; - } - - getBadges(authState.token.value, authState.client.id, authState.user.id) - .then((sets) => { - const tmp = sets.flatMap(({ set_id, versions }) => - versions.map(({ id, ...rest }) => [`${set_id}/${id}`, rest] as const) - ); - - if (keep) { - setBadges(new Map(tmp)); - } - }) - .catch((error: unknown) => { - console.error(error); - }); - - return () => { - keep = false; - }; - }, [authState]); - - return ( - - {children} - - ); -} diff --git a/src/hooks/useBadges.ts b/src/hooks/useBadges.ts new file mode 100644 index 0000000..8fe0de1 --- /dev/null +++ b/src/hooks/useBadges.ts @@ -0,0 +1,30 @@ +import { useQuery } from "@tanstack/react-query"; +import { getBadges, type Badge, type BadgeSet } from "../utils/api/getBadges"; +import { useContext } from "react"; +import { AuthContext } from "../contexts/auth-state/AuthContext"; + +type BadgeKey = `${BadgeSet["set_id"]}/${Badge["id"]}`; +type BadgeValue = Omit; +type TwitchBadges = Map; + +function makeBadgeMap(data: BadgeSet[]): TwitchBadges { + return new Map( + data.flatMap(({ set_id, versions }) => + versions.map(({ id, ...rest }) => [`${set_id}/${id}`, rest] as const) + ) + ); +} + +export function useBadges(userId?: string) { + const { authState } = useContext(AuthContext); + + const { data } = useQuery({ + enabled: !!authState, + queryKey: ["twitchBadges", userId], + // @ts-expect-error authState is not undefinend when query is exectued + queryFn: () => getBadges(authState, userId ?? authState?.user.id), + select: makeBadgeMap, + }); + + return data; +} diff --git a/src/utils/api/getBadges.ts b/src/utils/api/getBadges.ts index 4852179..7e7b62b 100644 --- a/src/utils/api/getBadges.ts +++ b/src/utils/api/getBadges.ts @@ -1,3 +1,5 @@ +import type { AuthState } from "../../contexts/auth-state/AuthContext"; + const CHANNEL_BADGES_URL = "https://api.twitch.tv/helix/chat/badges"; const GLOBAL_BADGES_URL = "https://api.twitch.tv/helix/chat/badges/global"; @@ -45,16 +47,19 @@ async function getBadgeSet( } export async function getBadges( - accessToken: string, - clientId: string, + authState: AuthState, userId: string ): Promise { const url = new URL(CHANNEL_BADGES_URL); url.searchParams.set("broadcaster_id", userId); const [channelBadges, globalBadges] = await Promise.all([ - await getBadgeSet(accessToken, clientId, url), - await getBadgeSet(accessToken, clientId, GLOBAL_BADGES_URL), + await getBadgeSet(authState.token.value, authState.client.id, url), + await getBadgeSet( + authState.token.value, + authState.client.id, + GLOBAL_BADGES_URL + ), ]); return [...globalBadges.data, ...channelBadges.data];