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];