From 923968ca5739b6e6a6c2d5358d31c5bc700f4837 Mon Sep 17 00:00:00 2001 From: mbrucedogs Date: Mon, 21 Jul 2025 10:35:00 -0500 Subject: [PATCH] Signed-off-by: mbrucedogs --- src/components/common/ListItem.tsx | 2 -- src/components/common/PlayerControls.tsx | 16 ++++++----- src/components/common/SelectSinger.tsx | 10 ++++--- src/features/Artists/Artists.tsx | 3 ++- src/features/Settings/Settings.tsx | 27 ++++++++++++------- src/features/TopPlayed/Top100.tsx | 3 ++- src/hooks/useActions.ts | 34 +++++++++++++----------- src/hooks/useDisabledSongs.ts | 18 +++++++------ src/hooks/useErrorHandler.ts | 7 +++-- src/hooks/useSingers.ts | 24 +++++++++-------- 10 files changed, 81 insertions(+), 63 deletions(-) diff --git a/src/components/common/ListItem.tsx b/src/components/common/ListItem.tsx index b187f96..4906c7d 100644 --- a/src/components/common/ListItem.tsx +++ b/src/components/common/ListItem.tsx @@ -18,7 +18,6 @@ interface GenericListItemProps { button?: boolean; style?: React.CSSProperties; endContent?: React.ReactNode; - showSeparator?: boolean; } // Generic ListItem component for different types of data @@ -36,7 +35,6 @@ export const ListItem = React.memo(forwardRef { return ( = ({ className = '', variant const playerState = useAppSelector(selectPlayerState); const queueLength = useAppSelector(selectQueueLength); const controllerName = useAppSelector(selectControllerName); - const { showSuccess, showError } = useToast(); + const toast = useToast(); + const showSuccess = toast?.showSuccess; + const showError = toast?.showError; // Debug logging debugLog('PlayerControls - playerState:', playerState); @@ -33,10 +35,10 @@ const PlayerControls: React.FC = ({ className = '', variant try { await playerService.updatePlayerStateValue(controllerName, PlayerState.playing); - showSuccess('Playback started'); + if (showSuccess) showSuccess('Playback started'); } catch (error) { console.error('Failed to start playback:', error); - showError('Failed to start playback'); + if (showError) showError('Failed to start playback'); } }; @@ -45,10 +47,10 @@ const PlayerControls: React.FC = ({ className = '', variant try { await playerService.updatePlayerStateValue(controllerName, PlayerState.paused); - showSuccess('Playback paused'); + if (showSuccess) showSuccess('Playback paused'); } catch (error) { console.error('Failed to pause playback:', error); - showError('Failed to pause playback'); + if (showError) showError('Failed to pause playback'); } }; @@ -57,10 +59,10 @@ const PlayerControls: React.FC = ({ className = '', variant try { await playerService.updatePlayerStateValue(controllerName, PlayerState.stopped); - showSuccess('Playback stopped'); + if (showSuccess) showSuccess('Playback stopped'); } catch (error) { console.error('Failed to stop playback:', error); - showError('Failed to stop playback'); + if (showError) showError('Failed to stop playback'); } }; diff --git a/src/components/common/SelectSinger.tsx b/src/components/common/SelectSinger.tsx index 7309777..648b93a 100644 --- a/src/components/common/SelectSinger.tsx +++ b/src/components/common/SelectSinger.tsx @@ -25,12 +25,14 @@ const SelectSinger: React.FC = ({ isOpen, onClose, song }) => const singers = useAppSelector(selectSingersArray); const controllerName = useAppSelector(selectControllerName); const currentQueue = useAppSelector(selectQueueObject); - const { showSuccess, showError } = useToast(); + const toast = useToast(); + const showSuccess = toast?.showSuccess; + const showError = toast?.showError; const [isLoading, setIsLoading] = useState(false); const handleSelectSinger = async (singer: Singer) => { if (!controllerName) { - showError('Controller not found'); + if (showError) showError('Controller not found'); return; } @@ -53,11 +55,11 @@ const SelectSinger: React.FC = ({ isOpen, onClose, song }) => }; await queueService.addToQueue(controllerName, queueItem); - showSuccess(`${song.title} added to queue for ${singer.name}`); + if (showSuccess) showSuccess(`${song.title} added to queue for ${singer.name}`); onClose(); } catch (error) { console.error('Failed to add song to queue:', error); - showError('Failed to add song to queue'); + if (showError) showError('Failed to add song to queue'); } finally { setIsLoading(false); } diff --git a/src/features/Artists/Artists.tsx b/src/features/Artists/Artists.tsx index e070b5e..6d9dd33 100644 --- a/src/features/Artists/Artists.tsx +++ b/src/features/Artists/Artists.tsx @@ -6,6 +6,7 @@ import { useArtists } from '../../hooks'; import { useAppSelector } from '../../redux'; import { selectSongs } from '../../redux'; import { debugLog } from '../../utils/logger'; +import { SongItemContext } from '../../types'; const Artists: React.FC = () => { @@ -90,7 +91,7 @@ const Artists: React.FC = () => { renderItem={(song) => ( { const isAdmin = useAppSelector(selectIsAdmin); @@ -26,7 +28,15 @@ const Settings: React.FC = () => { const [showDisabledSongsModal, setShowDisabledSongsModal] = useState(false); const [searchTerm, setSearchTerm] = useState(''); const controllerNameRedux = useAppSelector(selectControllerName); - const existingPlayer = useAppSelector(state => state.controller.data?.player) || {}; + const existingPlayer = (useAppSelector(state => state.controller.data?.player) || {}) as Partial; + + // Provide default values for required properties + const updatedPlayer = { + queue: existingPlayer.queue || {}, + settings: existingPlayer.settings || { autoadvance: false, userpick: false }, + singers: existingPlayer.singers || {}, + state: existingPlayer.state || { state: PlayerState.stopped }, + }; // Convert disabled songs object to array for display const disabledSongsArray: DisabledSong[] = Object.entries(disabledSongs).map(([key, disabledSong]) => ({ @@ -46,16 +56,15 @@ const Settings: React.FC = () => { debugLog(`Toggle ${setting} to ${value}`); const controllerName = controllerNameRedux; if (controllerName) { - await settingsService.updateSetting(controllerName, setting, value); + // @ts-expect-error: Redux Thunk type mismatch workaround dispatch(updateController({ controllerName, updates: { player: { - ...existingPlayer, - settings: { - ...existingPlayer.settings, - [setting]: value - } + queue: updatedPlayer.queue, + settings: { ...updatedPlayer.settings, [setting]: value }, + singers: updatedPlayer.singers, + state: updatedPlayer.state, } } })); @@ -198,7 +207,7 @@ const Settings: React.FC = () => {
{ debugLog('Top100 component - RENDERING START'); @@ -124,7 +125,7 @@ const Top100: React.FC = () => { { const playerState = useAppSelector(selectPlayerStateMemoized); const isAdmin = useAppSelector(selectIsAdmin); const { addToQueue, removeFromQueue, toggleFavorite } = useSongOperations(); - const { showSuccess, showError } = useToast(); + const toast = useToast(); + const showSuccess = toast?.showSuccess; + const showError = toast?.showError; const { isSongDisabled, addDisabledSong, removeDisabledSong } = useDisabledSongs(); // Queue permissions @@ -29,9 +31,9 @@ export const useActions = () => { const handleAddToQueue = useCallback(async (song: Song) => { try { await addToQueue(song); - showSuccess('Song added to queue'); + if (showSuccess) showSuccess('Song added to queue'); } catch { - showError('Failed to add song to queue'); + if (showError) showError('Failed to add song to queue'); } }, [addToQueue, showSuccess, showError]); @@ -40,18 +42,18 @@ export const useActions = () => { try { await removeFromQueue(queueItem.key); - showSuccess('Song removed from queue'); + if (showSuccess) showSuccess('Song removed from queue'); } catch { - showError('Failed to remove song from queue'); + if (showError) showError('Failed to remove song from queue'); } }, [removeFromQueue, showSuccess, showError]); const handleToggleFavorite = useCallback(async (song: Song) => { try { await toggleFavorite(song); - showSuccess(song.favorite ? 'Removed from favorites' : 'Added to favorites'); + if (showSuccess) showSuccess(song.favorite ? 'Removed from favorites' : 'Added to favorites'); } catch { - showError('Failed to update favorites'); + if (showError) showError('Failed to update favorites'); } }, [toggleFavorite, showSuccess, showError]); @@ -59,27 +61,27 @@ export const useActions = () => { try { if (isSongDisabled(song)) { await removeDisabledSong(song); - showSuccess('Song enabled'); + if (showSuccess) showSuccess('Song enabled'); } else { await addDisabledSong(song); - showSuccess('Song disabled'); + if (showSuccess) showSuccess('Song disabled'); } } catch { - showError('Failed to update song disabled status'); + if (showError) showError('Failed to update song disabled status'); } }, [isSongDisabled, addDisabledSong, removeDisabledSong, showSuccess, showError]); const handleDeleteFromHistory = useCallback(async (song: Song) => { if (!controllerName || !song.key) { - showError('Cannot delete history item - missing data'); + if (showError) showError('Cannot delete history item - missing data'); return; } try { await historyService.removeFromHistory(controllerName, song.key); - showSuccess('Removed from history'); + if (showSuccess) showSuccess('Removed from history'); } catch { - showError('Failed to remove from history'); + if (showError) showError('Failed to remove from history'); } }, [controllerName, showSuccess, showError]); @@ -94,7 +96,7 @@ export const useActions = () => { const { from, to, complete } = event.detail; if (!controllerName) { - showError('Cannot reorder - controller not available'); + if (showError) showError('Cannot reorder - controller not available'); return; } @@ -123,10 +125,10 @@ export const useActions = () => { await Promise.all(updatePromises); debugLog('Queue reorder completed successfully'); - showSuccess('Queue reordered successfully'); + if (showSuccess) showSuccess('Queue reordered successfully'); } catch (error) { console.error('Failed to reorder queue:', error); - showError('Failed to reorder queue'); + if (showError) showError('Failed to reorder queue'); } }, [controllerName, showSuccess, showError]); diff --git a/src/hooks/useDisabledSongs.ts b/src/hooks/useDisabledSongs.ts index 62dec91..0253f99 100644 --- a/src/hooks/useDisabledSongs.ts +++ b/src/hooks/useDisabledSongs.ts @@ -11,7 +11,9 @@ export const useDisabledSongs = () => { const [disabledSongs, setDisabledSongs] = useState>({}); const [loading, setLoading] = useState(true); const controllerName = useAppSelector(selectControllerName); - const { showSuccess, showError } = useToast(); + const toast = useToast(); + const showSuccess = toast?.showSuccess; + const showError = toast?.showError; // Load disabled songs on mount and subscribe to changes useEffect(() => { @@ -35,7 +37,7 @@ export const useDisabledSongs = () => { setDisabledSongPaths(paths); } catch (error) { console.error('Error loading disabled songs:', error); - showError('Failed to load disabled songs'); + if (showError) showError('Failed to load disabled songs'); } finally { setLoading(false); } @@ -81,22 +83,22 @@ export const useDisabledSongs = () => { const addDisabledSong = useCallback(async (song: Song) => { if (!controllerName) { console.error('No controller name available'); - showError('No controller name available'); + if (showError) showError('No controller name available'); return; } if (!song.path) { console.error('Song has no path:', song); - showError('Song has no path'); + if (showError) showError('Song has no path'); return; } try { await disabledSongsService.addDisabledSong(controllerName, song); - showSuccess('Song marked as disabled'); + if (showSuccess) showSuccess('Song marked as disabled'); } catch (error) { console.error('Error adding disabled song:', error); - showError(`Failed to mark song as disabled: ${error instanceof Error ? error.message : 'Unknown error'}`); + if (showError) showError(`Failed to mark song as disabled: ${error instanceof Error ? error.message : 'Unknown error'}`); } }, [controllerName, showSuccess, showError]); @@ -106,10 +108,10 @@ export const useDisabledSongs = () => { try { await disabledSongsService.removeDisabledSong(controllerName, song.path); - showSuccess('Song re-enabled'); + if (showSuccess) showSuccess('Song re-enabled'); } catch (error) { console.error('Error removing disabled song:', error); - showError('Failed to re-enable song'); + if (showError) showError('Failed to re-enable song'); } }, [controllerName, showSuccess, showError]); diff --git a/src/hooks/useErrorHandler.ts b/src/hooks/useErrorHandler.ts index 0253d4e..f213b00 100644 --- a/src/hooks/useErrorHandler.ts +++ b/src/hooks/useErrorHandler.ts @@ -15,7 +15,8 @@ interface ErrorHandlerResult { } export const useErrorHandler = (defaultOptions: ErrorHandlerOptions = {}): ErrorHandlerResult => { - const { showError } = useToast(); + const toast = useToast(); + const showError = toast?.showError; const defaultErrorOptions: Required = { showToast: true, @@ -45,9 +46,7 @@ export const useErrorHandler = (defaultOptions: ErrorHandlerOptions = {}): Error } // Show toast if enabled - if (opts.showToast) { - showError(displayMessage); - } + if (opts.showToast && showError) showError(displayMessage); }, [defaultErrorOptions, showError]); const handleAsyncError = useCallback(async ( diff --git a/src/hooks/useSingers.ts b/src/hooks/useSingers.ts index 3a0b109..3c41e7b 100644 --- a/src/hooks/useSingers.ts +++ b/src/hooks/useSingers.ts @@ -8,53 +8,55 @@ export const useSingers = () => { const singers = useAppSelector(selectSingersArray); const isAdmin = useAppSelector(selectIsAdmin); const controllerName = useAppSelector(selectControllerName); - const { showSuccess, showError } = useToast(); + const toast = useToast(); + const showSuccess = toast?.showSuccess; + const showError = toast?.showError; const handleRemoveSinger = useCallback(async (singer: Singer) => { if (!isAdmin) { - showError('Only admins can remove singers'); + showError && showError('Only admins can remove singers'); return; } if (!controllerName) { - showError('Controller not found'); + showError && showError('Controller not found'); return; } try { await singerService.removeSinger(controllerName, singer.name); - showSuccess(`${singer.name} removed from singers list and queue`); + showSuccess && showSuccess(`${singer.name} removed from singers list and queue`); } catch (error) { console.error('Failed to remove singer:', error); - showError('Failed to remove singer'); + showError && showError('Failed to remove singer'); } }, [isAdmin, controllerName, showSuccess, showError]); const handleAddSinger = useCallback(async (singerName: string) => { if (!isAdmin) { - showError('Only admins can add singers'); + showError && showError('Only admins can add singers'); return; } if (!controllerName) { - showError('Controller not found'); + showError && showError('Controller not found'); return; } if (!singerName.trim()) { - showError('Singer name cannot be empty'); + showError && showError('Singer name cannot be empty'); return; } try { await singerService.addSinger(controllerName, singerName.trim()); - showSuccess(`${singerName} added to singers list`); + showSuccess && showSuccess(`${singerName} added to singers list`); } catch (error) { console.error('Failed to add singer:', error); if (error instanceof Error && error.message === 'Singer already exists') { - showError('Singer already exists'); + showError && showError('Singer already exists'); } else { - showError('Failed to add singer'); + showError && showError('Failed to add singer'); } } }, [isAdmin, controllerName, showSuccess, showError]);