Signed-off-by: mbrucedogs <mbrucedogs@gmail.com>
This commit is contained in:
parent
fb2a06129d
commit
923968ca57
@ -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<HTMLIonItemElement, GenericListIte
|
||||
button = false,
|
||||
style,
|
||||
endContent,
|
||||
showSeparator, // keep for API compatibility, but not used
|
||||
}, ref) => {
|
||||
return (
|
||||
<IonItem
|
||||
|
||||
@ -21,7 +21,9 @@ const PlayerControls: React.FC<PlayerControlsProps> = ({ 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<PlayerControlsProps> = ({ 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<PlayerControlsProps> = ({ 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<PlayerControlsProps> = ({ 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');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -25,12 +25,14 @@ const SelectSinger: React.FC<SelectSingerProps> = ({ 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<SelectSingerProps> = ({ 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);
|
||||
}
|
||||
|
||||
@ -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) => (
|
||||
<SongItem
|
||||
song={song}
|
||||
context="search"
|
||||
context={SongItemContext.SEARCH}
|
||||
showAddButton={true}
|
||||
showInfoButton={true}
|
||||
showFavoriteButton={false}
|
||||
|
||||
@ -4,7 +4,6 @@ import { ban } from 'ionicons/icons';
|
||||
import { useAppSelector } from '../../redux';
|
||||
import { selectIsAdmin, selectSettings, updateController, selectControllerName } from '../../redux';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { settingsService } from '../../firebase/services';
|
||||
import { useDisabledSongs } from '../../hooks';
|
||||
import { InfiniteScrollList, ActionButton, SongItem } from '../../components/common';
|
||||
import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types';
|
||||
@ -12,6 +11,9 @@ import { Icons } from '../../constants';
|
||||
import { filterSongs } from '../../utils/dataProcessing';
|
||||
import { setDebugEnabled, isDebugEnabled, debugLog } from '../../utils/logger';
|
||||
import type { Song, DisabledSong } from '../../types';
|
||||
import { SongItemContext } from '../../types';
|
||||
import type { Controller } from '../../types';
|
||||
import { PlayerState } from '../../types';
|
||||
|
||||
const Settings: React.FC = () => {
|
||||
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<Controller['player']>;
|
||||
|
||||
// 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 = () => {
|
||||
<div className="flex-1">
|
||||
<SongItem
|
||||
song={song}
|
||||
context="history"
|
||||
context={SongItemContext.HISTORY}
|
||||
showDeleteButton={true}
|
||||
showInfoButton={false}
|
||||
showAddButton={false}
|
||||
|
||||
@ -10,6 +10,7 @@ import { debugLog } from '../../utils/logger';
|
||||
|
||||
|
||||
import type { TopPlayed } from '../../types';
|
||||
import { SongItemContext } from '../../types';
|
||||
|
||||
const Top100: React.FC = () => {
|
||||
debugLog('Top100 component - RENDERING START');
|
||||
@ -124,7 +125,7 @@ const Top100: React.FC = () => {
|
||||
<SongItem
|
||||
key={song.key || `${song.title}-${song.artist}`}
|
||||
song={song}
|
||||
context="search"
|
||||
context={SongItemContext.SEARCH}
|
||||
showAddButton={true}
|
||||
showInfoButton={true}
|
||||
showFavoriteButton={false}
|
||||
|
||||
@ -18,7 +18,9 @@ export const useActions = () => {
|
||||
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]);
|
||||
|
||||
|
||||
@ -11,7 +11,9 @@ export const useDisabledSongs = () => {
|
||||
const [disabledSongs, setDisabledSongs] = useState<Record<string, DisabledSong>>({});
|
||||
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]);
|
||||
|
||||
|
||||
@ -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<ErrorHandlerOptions> = {
|
||||
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 <T>(
|
||||
|
||||
@ -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]);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user