Files
lidify/frontend/features/home/hooks/useHomeData.ts
T
Kevin O'Neill f8b464feec v1.0.2: Mood mix optimizations and media player improvements
- Fixed player seek flicker on podcasts (30s skip buttons)
- Added dual-layer seek lock mechanism to prevent stale time updates
- Optimized cached podcast seeking (direct seek before reload fallback)
- Large skips now execute immediately for responsive feel
- Mood mix performance optimizations
2025-12-26 13:06:17 -06:00

163 lines
5.0 KiB
TypeScript

/**
* useHomeData Hook
*
* Manages data loading for the Home page, fetching all 7 sections using React Query
* and providing refresh functionality for mixes.
*/
import { useEffect } from "react";
import { useQueryClient } from "@tanstack/react-query";
import { useAuth } from "@/lib/auth-context";
import { toast } from "sonner";
import type {
Artist,
ListenedItem,
Podcast,
Audiobook,
Mix,
PopularArtist,
} from "../types";
import {
useRecentlyListenedQuery,
useRecentlyAddedQuery,
useRecommendationsQuery,
useMixesQuery,
usePopularArtistsQuery,
useTopPodcastsQuery,
useAudiobooksQuery,
useRefreshMixesMutation,
useBrowseAllQuery,
queryKeys,
} from "@/hooks/useQueries";
interface PlaylistPreview {
id: string;
source: string;
type: string;
title: string;
description: string | null;
creator: string;
imageUrl: string | null;
trackCount: number;
url: string;
}
export interface UseHomeDataReturn {
// Data sections
recentlyListened: ListenedItem[];
recentlyAdded: Artist[];
recommended: Artist[];
mixes: Mix[];
popularArtists: PopularArtist[];
recentPodcasts: Podcast[];
recentAudiobooks: Audiobook[];
featuredPlaylists: PlaylistPreview[];
// Loading states
isLoading: boolean;
isRefreshingMixes: boolean;
isBrowseLoading: boolean;
// Actions
handleRefreshMixes: () => Promise<void>;
}
/**
* Custom hook to load all Home page data sections using React Query
*
* Loads the following sections with automatic caching:
* 1. Recently listened (Continue Listening)
* 2. Recently added artists
* 3. Recommended for you
* 4. Mixes (Made For You)
* 5. Popular artists
* 6. Recent podcasts
* 7. Recent audiobooks
*
* @returns {UseHomeDataReturn} All home page data and loading states
*/
export function useHomeData(): UseHomeDataReturn {
const { isAuthenticated } = useAuth();
const queryClient = useQueryClient();
// Listen for mixes-updated event (fired when user saves mood preferences)
// Use refetchQueries instead of invalidateQueries to force immediate UI update
useEffect(() => {
const handleMixesUpdated = () => {
// refetchQueries forces immediate refetch, unlike invalidateQueries which only marks stale
queryClient.refetchQueries({ queryKey: queryKeys.mixes() });
};
window.addEventListener("mixes-updated", handleMixesUpdated);
return () =>
window.removeEventListener("mixes-updated", handleMixesUpdated);
}, [queryClient]);
// React Query hooks - these automatically handle caching, refetching, and loading states
const { data: recentlyListenedData, isLoading: isLoadingListened } =
useRecentlyListenedQuery(10);
const { data: recentlyAddedData, isLoading: isLoadingAdded } =
useRecentlyAddedQuery(10);
const { data: recommendedData, isLoading: isLoadingRecommended } =
useRecommendationsQuery(10);
const { data: mixesData, isLoading: isLoadingMixes } = useMixesQuery();
const { data: popularData, isLoading: isLoadingPopular } =
usePopularArtistsQuery(20);
const { data: podcastsData, isLoading: isLoadingPodcasts } =
useTopPodcastsQuery(10);
const { data: audiobooksData, isLoading: isLoadingAudiobooks } =
useAudiobooksQuery();
const { data: browseData, isLoading: isBrowseLoading } =
useBrowseAllQuery();
// Mutation for refreshing mixes
const { mutateAsync: refreshMixes, isPending: isRefreshingMixes } =
useRefreshMixesMutation();
/**
* Refresh mixes and update cache
*/
const handleRefreshMixes = async () => {
try {
await refreshMixes();
toast.success("Mixes refreshed! Check out your new daily picks");
} catch (error) {
console.error("Failed to refresh mixes:", error);
toast.error("Failed to refresh mixes");
}
};
// Process recently listened data - can contain artists, podcasts, or audiobooks
const items = recentlyListenedData?.items || [];
// Calculate overall loading state - true if any query is loading
const isLoading =
!isAuthenticated ||
isLoadingListened ||
isLoadingAdded ||
isLoadingRecommended ||
isLoadingMixes ||
isLoadingPopular ||
isLoadingPodcasts ||
isLoadingAudiobooks;
return {
recentlyListened: items,
recentlyAdded: recentlyAddedData?.artists || [],
recommended: recommendedData?.artists || [],
mixes: Array.isArray(mixesData) ? mixesData : [],
popularArtists: popularData?.artists || [],
recentPodcasts: Array.isArray(podcastsData)
? podcastsData.slice(0, 10)
: [],
recentAudiobooks: Array.isArray(audiobooksData)
? audiobooksData.slice(0, 10)
: [],
featuredPlaylists: browseData?.playlists || [],
isLoading,
isRefreshingMixes,
isBrowseLoading,
handleRefreshMixes,
};
}