diff --git a/src/constants/index.ts b/src/constants/index.ts index f0e42f9..58811d9 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -26,6 +26,9 @@ export const UI_CONSTANTS = { DEBOUNCE_DELAY: 300, MIN_SEARCH_LENGTH: 2, }, + PAGINATION: { + ITEMS_PER_PAGE: 20, + }, QUEUE: { MAX_ITEMS: 100, }, diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 09a104c..9f641c1 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -12,5 +12,6 @@ export { useSingers } from './useSingers'; export { useSongLists } from './useSongLists'; export { useDisabledSongs } from './useDisabledSongs'; export { useActions } from './useActions'; +export { usePagination } from './usePagination'; export { useSongInfo } from './useSongInfo'; \ No newline at end of file diff --git a/src/hooks/useArtists.ts b/src/hooks/useArtists.ts index 26aa2da..4db16aa 100644 --- a/src/hooks/useArtists.ts +++ b/src/hooks/useArtists.ts @@ -1,20 +1,15 @@ import { useCallback, useMemo, useState } from 'react'; import { useAppSelector, selectArtistsArray, selectSongsArray } from '../redux'; -import { debugLog } from '../utils/logger'; -import { useSongOperations } from './useSongOperations'; -import { useToast } from './useToast'; +import { useActions } from './useActions'; +import { usePagination } from './usePagination'; import type { Song } from '../types'; -const ITEMS_PER_PAGE = 20; - export const useArtists = () => { const allArtists = useAppSelector(selectArtistsArray); const allSongs = useAppSelector(selectSongsArray); - const { addToQueue, toggleFavorite } = useSongOperations(); - const { showSuccess, showError } = useToast(); + const { handleAddToQueue, handleToggleFavorite } = useActions(); const [searchTerm, setSearchTerm] = useState(''); - const [currentPage, setCurrentPage] = useState(1); // Pre-compute songs by artist and song counts for performance const songsByArtist = useMemo(() => { @@ -44,31 +39,8 @@ export const useArtists = () => { ); }, [allArtists, searchTerm]); - // Paginate the filtered artists - show all items up to current page - const artists = useMemo(() => { - const endIndex = currentPage * ITEMS_PER_PAGE; - return filteredArtists.slice(0, endIndex); - }, [filteredArtists, currentPage]); - - const hasMore = useMemo(() => { - // Show "hasMore" if there are more items than currently loaded - return filteredArtists.length > ITEMS_PER_PAGE && artists.length < filteredArtists.length; - }, [artists.length, filteredArtists.length]); - - const loadMore = useCallback(() => { - debugLog('useArtists - loadMore called:', { - hasMore, - currentPage, - filteredArtistsLength: filteredArtists.length, - artistsLength: artists.length - }); - if (hasMore) { - debugLog('useArtists - Incrementing page from', currentPage, 'to', currentPage + 1); - setCurrentPage(prev => prev + 1); - } else { - debugLog('useArtists - Not loading more because hasMore is false'); - } - }, [hasMore, currentPage, filteredArtists.length, artists.length]); + // Use unified pagination hook + const pagination = usePagination(filteredArtists); // Get songs by artist (now using cached data) const getSongsByArtist = useCallback((artistName: string) => { @@ -82,35 +54,17 @@ export const useArtists = () => { const handleSearchChange = useCallback((value: string) => { setSearchTerm(value); - setCurrentPage(1); // Reset to first page when searching - }, []); - - const handleAddToQueue = useCallback(async (song: Song) => { - try { - await addToQueue(song); - showSuccess('Song added to queue'); - } catch { - showError('Failed to add song to queue'); - } - }, [addToQueue, showSuccess, showError]); - - const handleToggleFavorite = useCallback(async (song: Song) => { - try { - await toggleFavorite(song); - showSuccess(song.favorite ? 'Removed from favorites' : 'Added to favorites'); - } catch { - showError('Failed to update favorites'); - } - }, [toggleFavorite, showSuccess, showError]); + pagination.resetPage(); // Reset to first page when searching + }, [pagination]); return { - artists, + artists: pagination.items, allArtists: filteredArtists, searchTerm, - hasMore, - loadMore, - currentPage, - totalPages: Math.ceil(filteredArtists.length / ITEMS_PER_PAGE), + hasMore: pagination.hasMore, + loadMore: pagination.loadMore, + currentPage: pagination.currentPage, + totalPages: pagination.totalPages, handleSearchChange, getSongsByArtist, getSongCountByArtist, diff --git a/src/hooks/useFavorites.ts b/src/hooks/useFavorites.ts index e77f90a..1a43ec6 100644 --- a/src/hooks/useFavorites.ts +++ b/src/hooks/useFavorites.ts @@ -1,20 +1,17 @@ -import { useCallback, useMemo, useState } from 'react'; +import { useMemo } from 'react'; import { useAppSelector, selectFavoritesArray } from '../redux'; import { debugLog } from '../utils/logger'; import { useActions } from './useActions'; +import { usePagination } from './usePagination'; import { useDisabledSongs } from './useDisabledSongs'; -const ITEMS_PER_PAGE = 20; - export const useFavorites = () => { const allFavoritesItems = useAppSelector(selectFavoritesArray); const { handleAddToQueue, handleToggleFavorite, handleToggleDisabled, isSongDisabled } = useActions(); const { disabledSongPaths, loading: disabledSongsLoading } = useDisabledSongs(); - - const [currentPage, setCurrentPage] = useState(1); - // Filter out disabled songs and paginate - const favoritesItems = useMemo(() => { + // Filter out disabled songs + const filteredItems = useMemo(() => { // Don't return any results if disabled songs are still loading if (disabledSongsLoading) { debugLog('useFavorites - disabled songs still loading, returning empty array'); @@ -22,37 +19,23 @@ export const useFavorites = () => { } // Filter out disabled songs first - const filteredItems = allFavoritesItems.filter(song => !disabledSongPaths.has(song.path)); - const endIndex = currentPage * ITEMS_PER_PAGE; + const filtered = allFavoritesItems.filter(song => !disabledSongPaths.has(song.path)); debugLog('useFavorites - filtering favorites:', { totalFavorites: allFavoritesItems.length, - afterDisabledFilter: filteredItems.length, - currentPage, - endIndex + afterDisabledFilter: filtered.length, }); - return filteredItems.slice(0, endIndex); - }, [allFavoritesItems, currentPage, disabledSongPaths, disabledSongsLoading]); + return filtered; + }, [allFavoritesItems, disabledSongPaths, disabledSongsLoading]); - const hasMore = useMemo(() => { - if (disabledSongsLoading) return false; - - const filteredItems = allFavoritesItems.filter(song => !disabledSongPaths.has(song.path)); - return filteredItems.length > ITEMS_PER_PAGE && favoritesItems.length < filteredItems.length; - }, [favoritesItems.length, allFavoritesItems, disabledSongPaths, disabledSongsLoading]); - - const loadMore = useCallback(() => { - debugLog('useFavorites - loadMore called:', { hasMore, currentPage, allFavoritesItemsLength: allFavoritesItems.length }); - if (hasMore) { - setCurrentPage(prev => prev + 1); - } - }, [hasMore, currentPage, allFavoritesItems.length]); + // Use unified pagination hook + const pagination = usePagination(filteredItems); return { - favoritesItems, - hasMore, - loadMore, + favoritesItems: pagination.items, + hasMore: pagination.hasMore, + loadMore: pagination.loadMore, handleAddToQueue, handleToggleFavorite, handleToggleDisabled, diff --git a/src/hooks/useHistory.ts b/src/hooks/useHistory.ts index cfcde6d..d8ed793 100644 --- a/src/hooks/useHistory.ts +++ b/src/hooks/useHistory.ts @@ -1,20 +1,17 @@ -import { useCallback, useMemo, useState } from 'react'; +import { useMemo } from 'react'; import { useAppSelector, selectHistoryArray } from '../redux'; import { debugLog } from '../utils/logger'; import { useActions } from './useActions'; +import { usePagination } from './usePagination'; import { useDisabledSongs } from './useDisabledSongs'; -const ITEMS_PER_PAGE = 20; - export const useHistory = () => { const allHistoryItems = useAppSelector(selectHistoryArray); const { handleAddToQueue, handleToggleFavorite, handleToggleDisabled, handleDeleteFromHistory, isSongDisabled } = useActions(); const { disabledSongPaths, loading: disabledSongsLoading } = useDisabledSongs(); - - const [currentPage, setCurrentPage] = useState(1); - // Filter out disabled songs and paginate - const historyItems = useMemo(() => { + // Filter out disabled songs + const filteredItems = useMemo(() => { // Don't return any results if disabled songs are still loading if (disabledSongsLoading) { debugLog('useHistory - disabled songs still loading, returning empty array'); @@ -22,37 +19,23 @@ export const useHistory = () => { } // Filter out disabled songs first - const filteredItems = allHistoryItems.filter(song => !disabledSongPaths.has(song.path)); - const endIndex = currentPage * ITEMS_PER_PAGE; + const filtered = allHistoryItems.filter(song => !disabledSongPaths.has(song.path)); debugLog('useHistory - filtering history:', { totalHistory: allHistoryItems.length, - afterDisabledFilter: filteredItems.length, - currentPage, - endIndex + afterDisabledFilter: filtered.length, }); - return filteredItems.slice(0, endIndex); - }, [allHistoryItems, currentPage, disabledSongPaths, disabledSongsLoading]); + return filtered; + }, [allHistoryItems, disabledSongPaths, disabledSongsLoading]); - const hasMore = useMemo(() => { - if (disabledSongsLoading) return false; - - const filteredItems = allHistoryItems.filter(song => !disabledSongPaths.has(song.path)); - return filteredItems.length > ITEMS_PER_PAGE && historyItems.length < filteredItems.length; - }, [historyItems.length, allHistoryItems, disabledSongPaths, disabledSongsLoading]); - - const loadMore = useCallback(() => { - debugLog('useHistory - loadMore called:', { hasMore, currentPage, allHistoryItemsLength: allHistoryItems.length }); - if (hasMore) { - setCurrentPage(prev => prev + 1); - } - }, [hasMore, currentPage, allHistoryItems.length]); + // Use unified pagination hook + const pagination = usePagination(filteredItems); return { - historyItems, - hasMore, - loadMore, + historyItems: pagination.items, + hasMore: pagination.hasMore, + loadMore: pagination.loadMore, handleAddToQueue, handleToggleFavorite, handleToggleDisabled, diff --git a/src/hooks/useNewSongs.ts b/src/hooks/useNewSongs.ts index 031f604..aa8b9e6 100644 --- a/src/hooks/useNewSongs.ts +++ b/src/hooks/useNewSongs.ts @@ -1,23 +1,17 @@ -import { useCallback, useMemo, useState } from 'react'; +import { useMemo } from 'react'; import { useAppSelector, selectNewSongsArray } from '../redux'; import { debugLog } from '../utils/logger'; -import { useSongOperations } from './useSongOperations'; -import { useToast } from './useToast'; +import { useActions } from './useActions'; +import { usePagination } from './usePagination'; import { useDisabledSongs } from './useDisabledSongs'; -import type { Song } from '../types'; - -const ITEMS_PER_PAGE = 20; export const useNewSongs = () => { const allNewSongsItems = useAppSelector(selectNewSongsArray); - const { addToQueue, toggleFavorite } = useSongOperations(); - const { showSuccess, showError } = useToast(); - const { disabledSongPaths, isSongDisabled, addDisabledSong, removeDisabledSong, loading: disabledSongsLoading } = useDisabledSongs(); - - const [currentPage, setCurrentPage] = useState(1); + const { handleAddToQueue, handleToggleFavorite, handleToggleDisabled, isSongDisabled } = useActions(); + const { disabledSongPaths, loading: disabledSongsLoading } = useDisabledSongs(); - // Filter out disabled songs and paginate - const newSongsItems = useMemo(() => { + // Filter out disabled songs + const filteredItems = useMemo(() => { // Don't return any results if disabled songs are still loading if (disabledSongsLoading) { debugLog('useNewSongs - disabled songs still loading, returning empty array'); @@ -25,67 +19,23 @@ export const useNewSongs = () => { } // Filter out disabled songs first - const filteredItems = allNewSongsItems.filter(song => !disabledSongPaths.has(song.path)); - const endIndex = currentPage * ITEMS_PER_PAGE; + const filtered = allNewSongsItems.filter(song => !disabledSongPaths.has(song.path)); debugLog('useNewSongs - filtering new songs:', { totalNewSongs: allNewSongsItems.length, - afterDisabledFilter: filteredItems.length, - currentPage, - endIndex + afterDisabledFilter: filtered.length, }); - return filteredItems.slice(0, endIndex); - }, [allNewSongsItems, currentPage, disabledSongPaths, disabledSongsLoading]); + return filtered; + }, [allNewSongsItems, disabledSongPaths, disabledSongsLoading]); - const hasMore = useMemo(() => { - if (disabledSongsLoading) return false; - - const filteredItems = allNewSongsItems.filter(song => !disabledSongPaths.has(song.path)); - return filteredItems.length > ITEMS_PER_PAGE && newSongsItems.length < filteredItems.length; - }, [newSongsItems.length, allNewSongsItems, disabledSongPaths, disabledSongsLoading]); - - const loadMore = useCallback(() => { - debugLog('useNewSongs - loadMore called:', { hasMore, currentPage, allNewSongsItemsLength: allNewSongsItems.length }); - if (hasMore) { - setCurrentPage(prev => prev + 1); - } - }, [hasMore, currentPage, allNewSongsItems.length]); - - const handleAddToQueue = useCallback(async (song: Song) => { - try { - await addToQueue(song); - showSuccess('Song added to queue'); - } catch { - showError('Failed to add song to queue'); - } - }, [addToQueue, showSuccess, showError]); - - const handleToggleFavorite = useCallback(async (song: Song) => { - try { - await toggleFavorite(song); - showSuccess(song.favorite ? 'Removed from favorites' : 'Added to favorites'); - } catch { - showError('Failed to update favorites'); - } - }, [toggleFavorite, showSuccess, showError]); - - const handleToggleDisabled = useCallback(async (song: Song) => { - try { - if (isSongDisabled(song)) { - await removeDisabledSong(song); - } else { - await addDisabledSong(song); - } - } catch { - showError('Failed to update song disabled status'); - } - }, [isSongDisabled, addDisabledSong, removeDisabledSong, showError]); + // Use unified pagination hook + const pagination = usePagination(filteredItems); return { - newSongsItems, - hasMore, - loadMore, + newSongsItems: pagination.items, + hasMore: pagination.hasMore, + loadMore: pagination.loadMore, handleAddToQueue, handleToggleFavorite, handleToggleDisabled, diff --git a/src/hooks/usePagination.ts b/src/hooks/usePagination.ts new file mode 100644 index 0000000..d0e856a --- /dev/null +++ b/src/hooks/usePagination.ts @@ -0,0 +1,88 @@ +import { useState, useCallback, useMemo } from 'react'; +import { UI_CONSTANTS } from '../constants'; + +export interface PaginationConfig { + itemsPerPage?: number; + initialPage?: number; +} + +export interface PaginationResult { + // Current state + currentPage: number; + items: T[]; + hasMore: boolean; + + // Actions + loadMore: () => void; + resetPage: () => void; + setPage: (page: number) => void; + + // Computed values + totalItems: number; + totalPages: number; + startIndex: number; + endIndex: number; +} + +export const usePagination = ( + allItems: T[], + config: PaginationConfig = {} +): PaginationResult => { + const { + itemsPerPage = UI_CONSTANTS.PAGINATION.ITEMS_PER_PAGE, + initialPage = 1 + } = config; + + const [currentPage, setCurrentPage] = useState(initialPage); + + // Calculate pagination values + const totalItems = allItems.length; + const totalPages = Math.ceil(totalItems / itemsPerPage); + const startIndex = 0; + const endIndex = currentPage * itemsPerPage; + + // Get paginated items + const items = useMemo(() => { + return allItems.slice(startIndex, endIndex); + }, [allItems, endIndex]); + + // Check if there are more items to load + const hasMore = useMemo(() => { + return totalItems > itemsPerPage && items.length < totalItems; + }, [totalItems, itemsPerPage, items.length]); + + // Load more items + const loadMore = useCallback(() => { + if (hasMore) { + setCurrentPage(prev => prev + 1); + } + }, [hasMore]); + + // Reset to first page + const resetPage = useCallback(() => { + setCurrentPage(initialPage); + }, [initialPage]); + + // Set specific page + const setPage = useCallback((page: number) => { + setCurrentPage(page); + }, []); + + return { + // Current state + currentPage, + items, + hasMore, + + // Actions + loadMore, + resetPage, + setPage, + + // Computed values + totalItems, + totalPages, + startIndex, + endIndex, + }; +}; \ No newline at end of file diff --git a/src/hooks/useSearch.ts b/src/hooks/useSearch.ts index 76cf9d9..a1dc2ce 100644 --- a/src/hooks/useSearch.ts +++ b/src/hooks/useSearch.ts @@ -1,16 +1,14 @@ import { useState, useCallback, useMemo } from 'react'; import { useAppSelector, selectSongsArray } from '../redux'; import { useActions } from './useActions'; +import { usePagination } from './usePagination'; import { useDisabledSongs } from './useDisabledSongs'; import { UI_CONSTANTS } from '../constants'; import { filterSongs } from '../utils/dataProcessing'; import { debugLog } from '../utils/logger'; -const ITEMS_PER_PAGE = 20; - export const useSearch = () => { const [searchTerm, setSearchTerm] = useState(''); - const [currentPage, setCurrentPage] = useState(1); const { handleAddToQueue, handleToggleFavorite, handleToggleDisabled, isSongDisabled } = useActions(); const { disabledSongPaths, loading: disabledSongsLoading } = useDisabledSongs(); @@ -58,30 +56,22 @@ export const useSearch = () => { return filtered; }, [allSongs, searchTerm, disabledSongPaths, disabledSongsLoading]); - // Paginate the filtered results - show all items up to current page - const searchResults = useMemo(() => { - const endIndex = currentPage * ITEMS_PER_PAGE; - const paginatedSongs = filteredSongs.slice(0, endIndex); - - return { - songs: paginatedSongs, - count: filteredSongs.length, - hasMore: endIndex < filteredSongs.length, - currentPage, - totalPages: Math.ceil(filteredSongs.length / ITEMS_PER_PAGE), - }; - }, [filteredSongs, currentPage]); + // Use unified pagination hook + const pagination = usePagination(filteredSongs); const handleSearchChange = useCallback((value: string) => { setSearchTerm(value); - setCurrentPage(1); // Reset to first page when searching - }, []); + pagination.resetPage(); // Reset to first page when searching + }, [pagination]); - const loadMore = useCallback(() => { - if (searchResults.hasMore) { - setCurrentPage(prev => prev + 1); - } - }, [searchResults.hasMore]); + // Create search results object for backward compatibility + const searchResults = useMemo(() => ({ + songs: pagination.items, + count: pagination.totalItems, + hasMore: pagination.hasMore, + currentPage: pagination.currentPage, + totalPages: pagination.totalPages, + }), [pagination]); return { searchTerm, @@ -90,7 +80,7 @@ export const useSearch = () => { handleAddToQueue, handleToggleFavorite, handleToggleDisabled, - loadMore, + loadMore: pagination.loadMore, isSongDisabled, }; }; \ No newline at end of file diff --git a/src/hooks/useSongLists.ts b/src/hooks/useSongLists.ts index f461c7e..3a13e7c 100644 --- a/src/hooks/useSongLists.ts +++ b/src/hooks/useSongLists.ts @@ -1,56 +1,16 @@ -import { useCallback, useMemo, useState } from 'react'; +import { useCallback } from 'react'; import { useAppSelector, selectSongListArray, selectSongsArray } from '../redux'; -import { debugLog } from '../utils/logger'; -import { useSongOperations } from './useSongOperations'; -import { useToast } from './useToast'; -import type { SongListSong, Song } from '../types'; - -const ITEMS_PER_PAGE = 20; +import { useActions } from './useActions'; +import { usePagination } from './usePagination'; +import type { SongListSong } from '../types'; export const useSongLists = () => { const allSongLists = useAppSelector(selectSongListArray); const allSongs = useAppSelector(selectSongsArray); - const { addToQueue, toggleFavorite } = useSongOperations(); - const { showSuccess, showError } = useToast(); - - const [currentPage, setCurrentPage] = useState(1); + const { handleAddToQueue, handleToggleFavorite } = useActions(); - // Paginate the song lists - show all items up to current page - const songLists = useMemo(() => { - const endIndex = currentPage * ITEMS_PER_PAGE; - return allSongLists.slice(0, endIndex); - }, [allSongLists, currentPage]); - - const hasMore = useMemo(() => { - // Show "hasMore" if there are more items than currently loaded - const hasMoreItems = songLists.length < allSongLists.length; - debugLog('useSongLists - hasMore calculation:', { - songListsLength: songLists.length, - allSongListsLength: allSongLists.length, - hasMore: hasMoreItems, - currentPage - }); - return hasMoreItems; - }, [songLists.length, allSongLists.length, currentPage]); - - const loadMore = useCallback(() => { - const endIndex = currentPage * ITEMS_PER_PAGE; - const hasMoreItems = endIndex < allSongLists.length; - - debugLog('useSongLists - loadMore called:', { - hasMoreItems, - currentPage, - allSongListsLength: allSongLists.length, - endIndex - }); - - if (hasMoreItems) { - debugLog('useSongLists - Incrementing page from', currentPage, 'to', currentPage + 1); - setCurrentPage(prev => prev + 1); - } else { - debugLog('useSongLists - Not loading more because hasMore is false'); - } - }, [currentPage, allSongLists.length]); + // Use unified pagination hook + const pagination = usePagination(allSongLists); // Check if a song exists in the catalog const checkSongAvailability = useCallback((songListSong: SongListSong) => { @@ -67,31 +27,13 @@ export const useSongLists = () => { return matchingSongs; }, [allSongs]); - const handleAddToQueue = useCallback(async (song: Song) => { - try { - await addToQueue(song); - showSuccess('Song added to queue'); - } catch { - showError('Failed to add song to queue'); - } - }, [addToQueue, showSuccess, showError]); - - const handleToggleFavorite = useCallback(async (song: Song) => { - try { - await toggleFavorite(song); - showSuccess(song.favorite ? 'Removed from favorites' : 'Added to favorites'); - } catch { - showError('Failed to update favorites'); - } - }, [toggleFavorite, showSuccess, showError]); - return { - songLists, + songLists: pagination.items, allSongLists, - hasMore, - loadMore, - currentPage, - totalPages: Math.ceil(allSongLists.length / ITEMS_PER_PAGE), + hasMore: pagination.hasMore, + loadMore: pagination.loadMore, + currentPage: pagination.currentPage, + totalPages: pagination.totalPages, checkSongAvailability, handleAddToQueue, handleToggleFavorite, diff --git a/src/hooks/useTopPlayed.ts b/src/hooks/useTopPlayed.ts index 5f83e49..c633a5b 100644 --- a/src/hooks/useTopPlayed.ts +++ b/src/hooks/useTopPlayed.ts @@ -1,97 +1,42 @@ -import { useCallback, useMemo, useState } from 'react'; +import { useCallback, useState } from 'react'; import { useAppSelector, selectTopPlayedArray } from '../redux'; import { debugLog } from '../utils/logger'; -import { useSongOperations } from './useSongOperations'; -import { useToast } from './useToast'; -import type { TopPlayed } from '../types'; - -const ITEMS_PER_PAGE = 20; +import { useActions } from './useActions'; +import { usePagination } from './usePagination'; export const useTopPlayed = () => { const allTopPlayedItems = useAppSelector(selectTopPlayedArray); - const { addToQueue, toggleFavorite } = useSongOperations(); - const { showSuccess, showError } = useToast(); + const { handleAddToQueue, handleToggleFavorite } = useActions(); - const [currentPage, setCurrentPage] = useState(1); const [isLoading, setIsLoading] = useState(false); - // Paginate the top played items - show all items up to current page - const topPlayedItems = useMemo(() => { - const endIndex = currentPage * ITEMS_PER_PAGE; - const result = allTopPlayedItems.slice(0, endIndex); - debugLog('useTopPlayed - pagination:', { - currentPage, - ITEMS_PER_PAGE, - endIndex, - allTopPlayedItemsLength: allTopPlayedItems.length, - resultLength: result.length - }); - return result; - }, [allTopPlayedItems, currentPage]); - - const hasMore = useMemo(() => { - // Show "hasMore" if there are more items than currently loaded - const result = topPlayedItems.length < allTopPlayedItems.length; - debugLog('useTopPlayed - hasMore calculation:', { - topPlayedItemsLength: topPlayedItems.length, - allTopPlayedItemsLength: allTopPlayedItems.length, - result - }); - return result; - }, [topPlayedItems.length, allTopPlayedItems.length]); + // Use unified pagination hook + const pagination = usePagination(allTopPlayedItems); const loadMore = useCallback(() => { - debugLog('useTopPlayed - loadMore called:', { hasMore, currentPage, allTopPlayedItemsLength: allTopPlayedItems.length }); - if (hasMore && !isLoading) { + debugLog('useTopPlayed - loadMore called:', { + hasMore: pagination.hasMore, + currentPage: pagination.currentPage, + allTopPlayedItemsLength: allTopPlayedItems.length + }); + if (pagination.hasMore && !isLoading) { setIsLoading(true); // Simulate a small delay to show loading state setTimeout(() => { - setCurrentPage(prev => prev + 1); + pagination.loadMore(); setIsLoading(false); }, 100); } - }, [hasMore, currentPage, allTopPlayedItems.length, isLoading]); - - const handleAddToQueue = useCallback(async (song: TopPlayed) => { - try { - // Convert TopPlayed to Song format for queue - const songForQueue = { - ...song, - path: '', // TopPlayed doesn't have path - disabled: false, - favorite: false, - }; - await addToQueue(songForQueue); - showSuccess('Song added to queue'); - } catch { - showError('Failed to add song to queue'); - } - }, [addToQueue, showSuccess, showError]); - - const handleToggleFavorite = useCallback(async (song: TopPlayed) => { - try { - // Convert TopPlayed to Song format for favorites - const songForFavorites = { - ...song, - path: '', // TopPlayed doesn't have path - disabled: false, - favorite: false, - }; - await toggleFavorite(songForFavorites); - showSuccess(songForFavorites.favorite ? 'Removed from favorites' : 'Added to favorites'); - } catch { - showError('Failed to update favorites'); - } - }, [toggleFavorite, showSuccess, showError]); + }, [pagination, allTopPlayedItems.length, isLoading]); return { - topPlayedItems, + topPlayedItems: pagination.items, allTopPlayedItems, - hasMore, + hasMore: pagination.hasMore, loadMore, isLoading, - currentPage, - totalPages: Math.ceil(allTopPlayedItems.length / ITEMS_PER_PAGE), + currentPage: pagination.currentPage, + totalPages: pagination.totalPages, handleAddToQueue, handleToggleFavorite, };