singsalot/src/redux/selectors.ts

165 lines
5.0 KiB
TypeScript

import { createSelector } from '@reduxjs/toolkit';
import type { RootState } from '../types';
import {
selectSongs,
selectQueue,
selectFavorites,
selectHistory,
selectTopPlayed,
selectNewSongs,
selectSongList,
selectSingers,
selectIsAdmin,
selectCurrentSinger
} from './index';
import {
objectToArray,
filterSongs,
sortQueueByOrder,
sortHistoryByDate,
sortTopPlayedByCount,
sortSongsByArtistAndTitle,
limitArray,
getQueueStats
} from '../utils/dataProcessing';
import { UI_CONSTANTS } from '../constants';
// Enhanced selectors with data processing
export const selectSongsArray = createSelector(
[selectSongs],
(songs) => sortSongsByArtistAndTitle(objectToArray(songs))
);
// Selector that filters songs and excludes disabled ones
export const selectSongsArrayWithoutDisabled = createSelector(
[selectSongsArray, (_state: RootState, disabledSongPaths: Set<string>) => disabledSongPaths],
(songs, disabledSongPaths) => songs.filter(song => !disabledSongPaths.has(song.path))
);
export const selectFilteredSongs = createSelector(
[selectSongsArray, (_state: RootState, searchTerm: string) => searchTerm],
(songs, searchTerm) => filterSongs(songs, searchTerm)
);
// Enhanced filtered songs that also excludes disabled songs
export const selectFilteredSongsWithoutDisabled = createSelector(
[selectSongsArray, (_state: RootState, searchTerm: string, disabledSongPaths: Set<string>) => ({ searchTerm, disabledSongPaths })],
(songs, { searchTerm, disabledSongPaths }) => filterSongs(songs, searchTerm, disabledSongPaths)
);
export const selectQueueArray = createSelector(
[selectQueue],
(queue) => sortQueueByOrder(objectToArray(queue))
);
export const selectQueueStats = createSelector(
[selectQueue],
(queue) => getQueueStats(queue)
);
export const selectHistoryArray = createSelector(
[selectHistory],
(history) => limitArray(sortHistoryByDate(objectToArray(history)), UI_CONSTANTS.HISTORY.MAX_ITEMS)
);
// History array without disabled songs
export const selectHistoryArrayWithoutDisabled = createSelector(
[selectHistoryArray, (_state: RootState, disabledSongPaths: Set<string>) => disabledSongPaths],
(history, disabledSongPaths) => history.filter(song => !disabledSongPaths.has(song.path))
);
export const selectFavoritesArray = createSelector(
[selectFavorites],
(favorites) => sortSongsByArtistAndTitle(objectToArray(favorites))
);
// Favorites array without disabled songs
export const selectFavoritesArrayWithoutDisabled = createSelector(
[selectFavoritesArray, (_state: RootState, disabledSongPaths: Set<string>) => disabledSongPaths],
(favorites, disabledSongPaths) => favorites.filter(song => !disabledSongPaths.has(song.path))
);
export const selectNewSongsArray = createSelector(
[selectNewSongs],
(newSongs) => sortSongsByArtistAndTitle(objectToArray(newSongs))
);
// New songs array without disabled songs
export const selectNewSongsArrayWithoutDisabled = createSelector(
[selectNewSongsArray, (_state: RootState, disabledSongPaths: Set<string>) => disabledSongPaths],
(newSongs, disabledSongPaths) => newSongs.filter(song => !disabledSongPaths.has(song.path))
);
export const selectSingersArray = createSelector(
[selectSingers],
(singers) => objectToArray(singers).sort((a, b) => a.name.localeCompare(b.name))
);
export const selectSongListArray = createSelector(
[selectSongList],
(songList) => objectToArray(songList)
);
export const selectArtistsArray = createSelector(
[selectSongs],
(songs) => {
const artists = new Set<string>();
Object.values(songs).forEach(song => {
if (song.artist) {
artists.add(song.artist);
}
});
return Array.from(artists).sort((a, b) => a.localeCompare(b));
}
);
export const selectTopPlayedArray = createSelector(
[selectTopPlayed],
(topPlayed) => sortTopPlayedByCount(objectToArray(topPlayed))
);
// User-specific selectors
export const selectUserQueueItems = createSelector(
[selectQueueArray, selectCurrentSinger],
(queueArray, currentSinger) =>
queueArray.filter(item => item.singer.name === currentSinger)
);
export const selectCanReorderQueue = createSelector(
[selectIsAdmin],
(isAdmin) => isAdmin
);
// Search-specific selectors
export const selectSearchResults = createSelector(
[selectFilteredSongs],
(filteredSongs) => ({
songs: filteredSongs,
count: filteredSongs.length,
})
);
// Enhanced search results that exclude disabled songs
export const selectSearchResultsWithoutDisabled = createSelector(
[selectFilteredSongsWithoutDisabled],
(filteredSongs) => ({
songs: filteredSongs,
count: filteredSongs.length,
})
);
// Queue-specific selectors
export const selectQueueWithUserInfo = createSelector(
[selectQueueArray, selectCurrentSinger],
(queueArray, currentSinger) =>
queueArray.map(item => ({
...item,
isCurrentUser: item.singer.name === currentSinger,
}))
);
// Memoized selector for queue length to prevent unnecessary re-renders
export const selectQueueLength = createSelector(
[selectQueue],
(queue) => Object.keys(queue).length
);