diff --git a/src/api/knowledge/types.ts b/src/api/knowledge/types.ts new file mode 100644 index 00000000..294b7c3a --- /dev/null +++ b/src/api/knowledge/types.ts @@ -0,0 +1,4 @@ +export const knowledgeKeys = { + all: ["knowledge"] as const, + user: (userId: string) => [...knowledgeKeys.all, "user", userId] as const, +}; diff --git a/src/api/knowledge/useKnowledge.ts b/src/api/knowledge/useKnowledge.ts new file mode 100644 index 00000000..20e6846c --- /dev/null +++ b/src/api/knowledge/useKnowledge.ts @@ -0,0 +1,34 @@ +import { useAuth } from "@/contexts/AuthContext"; +import { useUserKnowledgeQuery } from "./useUserKnowledgeQuery"; +import { useKnowledgeToggleMutation } from "./useKnowledgeToggleMutation"; + +export function useKnowledge() { + const { user } = useAuth(); + const { data: userKnowledge = {} } = useUserKnowledgeQuery(user?.id); + const knowledgeToggleMutation = useKnowledgeToggleMutation(); + + async function handleKnowledgeToggle(artistId: string) { + if (!user) { + return { requiresAuth: true }; + } + + const isKnown = userKnowledge[artistId]; + + try { + await knowledgeToggleMutation.mutateAsync({ + artistId, + userId: user.id, + isKnown, + }); + return { requiresAuth: false }; + } catch (error) { + console.error("failed toggling knowledge", error); + return { requiresAuth: false }; + } + } + + return { + userKnowledge, + handleKnowledgeToggle, + }; +} diff --git a/src/hooks/queries/knowledge/useKnowledge.ts b/src/api/knowledge/useKnowledgeToggleMutation.ts similarity index 51% rename from src/hooks/queries/knowledge/useKnowledge.ts rename to src/api/knowledge/useKnowledgeToggleMutation.ts index 80e81a3a..af4ed689 100644 --- a/src/hooks/queries/knowledge/useKnowledge.ts +++ b/src/api/knowledge/useKnowledgeToggleMutation.ts @@ -1,35 +1,7 @@ -import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; import { useToast } from "@/hooks/use-toast"; import { supabase } from "@/integrations/supabase/client"; -import { useAuth } from "@/contexts/AuthContext"; - -// Query key factory -export const knowledgeKeys = { - all: ["knowledge"] as const, - user: (userId: string) => [...knowledgeKeys.all, "user", userId] as const, -}; - -// Business logic functions -async function fetchUserKnowledge( - userId: string, -): Promise> { - const { data, error } = await supabase - .from("artist_knowledge") - .select("artist_id") - .eq("user_id", userId); - - if (error) { - throw new Error("Failed to fetch user knowledge"); - } - - return (data || []).reduce( - (acc, knowledge) => { - acc[knowledge.artist_id] = true; - return acc; - }, - {} as Record, - ); -} +import { knowledgeKeys } from "./types"; async function toggleKnowledge(variables: { artistId: string; @@ -58,15 +30,6 @@ async function toggleKnowledge(variables: { } } -// Hooks -export function useUserKnowledgeQuery(userId: string | undefined) { - return useQuery({ - queryKey: knowledgeKeys.user(userId || ""), - queryFn: () => fetchUserKnowledge(userId!), - enabled: !!userId, - }); -} - export function useKnowledgeToggleMutation() { const queryClient = useQueryClient(); const { toast } = useToast(); @@ -76,17 +39,14 @@ export function useKnowledgeToggleMutation() { onMutate: async (variables) => { const { artistId, userId, isKnown } = variables; - // Cancel any outgoing refetches await queryClient.cancelQueries({ queryKey: knowledgeKeys.user(userId), }); - // Snapshot the previous value const previousKnowledge = queryClient.getQueryData< Record >(knowledgeKeys.user(userId)); - // Optimistically update to the new value queryClient.setQueryData>( knowledgeKeys.user(userId), (old) => { @@ -94,10 +54,8 @@ export function useKnowledgeToggleMutation() { const newKnowledge = { ...old }; if (isKnown) { - // Remove knowledge delete newKnowledge[artistId]; } else { - // Add knowledge newKnowledge[artistId] = true; } @@ -108,7 +66,6 @@ export function useKnowledgeToggleMutation() { return { previousKnowledge, userId }; }, onError: (_error, _variables, context) => { - // If the mutation fails, use the context returned from onMutate to roll back if (context?.previousKnowledge) { queryClient.setQueryData( knowledgeKeys.user(context.userId), @@ -123,41 +80,9 @@ export function useKnowledgeToggleMutation() { }); }, onSettled: (_data, _error, variables) => { - // Always refetch after error or success to ensure consistency queryClient.invalidateQueries({ queryKey: knowledgeKeys.user(variables.userId), }); }, }); } - -export function useKnowledge() { - const { user } = useAuth(); - const { data: userKnowledge = {} } = useUserKnowledgeQuery(user?.id); - const knowledgeToggleMutation = useKnowledgeToggleMutation(); - - async function handleKnowledgeToggle(artistId: string) { - if (!user) { - return { requiresAuth: true }; - } - - const isKnown = userKnowledge[artistId]; - - try { - await knowledgeToggleMutation.mutateAsync({ - artistId, - userId: user.id, - isKnown, - }); - return { requiresAuth: false }; - } catch (error) { - console.error("failed toggling knowledge", error); - return { requiresAuth: false }; - } - } - - return { - userKnowledge, - handleKnowledgeToggle, - }; -} diff --git a/src/api/knowledge/useUserKnowledgeQuery.ts b/src/api/knowledge/useUserKnowledgeQuery.ts new file mode 100644 index 00000000..4bf26d37 --- /dev/null +++ b/src/api/knowledge/useUserKnowledgeQuery.ts @@ -0,0 +1,38 @@ +import { queryOptions, useQuery } from "@tanstack/react-query"; +import { supabase } from "@/integrations/supabase/client"; +import { knowledgeKeys } from "./types"; + +async function fetchUserKnowledge( + userId: string, +): Promise> { + const { data, error } = await supabase + .from("artist_knowledge") + .select("artist_id") + .eq("user_id", userId); + + if (error) { + throw new Error("Failed to fetch user knowledge"); + } + + return (data || []).reduce( + (acc, knowledge) => { + acc[knowledge.artist_id] = true; + return acc; + }, + {} as Record, + ); +} + +export function userKnowledgeQuery(userId: string) { + return queryOptions({ + queryKey: knowledgeKeys.user(userId), + queryFn: () => fetchUserKnowledge(userId), + }); +} + +export function useUserKnowledgeQuery(userId: string | undefined) { + return useQuery({ + ...userKnowledgeQuery(userId ?? ""), + enabled: !!userId, + }); +}