Signed-off-by: mbrucedogs <mbrucedogs@gmail.com>
This commit is contained in:
parent
debabcc9e7
commit
551b180f54
@ -8,7 +8,7 @@ import {
|
|||||||
} from 'ionicons/icons';
|
} from 'ionicons/icons';
|
||||||
import { useAppSelector } from '../../redux';
|
import { useAppSelector } from '../../redux';
|
||||||
import { selectIsAdmin, selectFavorites, selectSongs, selectQueue } from '../../redux';
|
import { selectIsAdmin, selectFavorites, selectSongs, selectQueue } from '../../redux';
|
||||||
import { useActionHandlers } from '../../hooks/useActionHandlers';
|
import { useActions } from '../../hooks/useActions';
|
||||||
import { useModal } from '../../hooks/useModalContext';
|
import { useModal } from '../../hooks/useModalContext';
|
||||||
|
|
||||||
import { ModalHeader } from './ModalHeader';
|
import { ModalHeader } from './ModalHeader';
|
||||||
@ -26,7 +26,7 @@ const SongInfo: React.FC<SongInfoProps> = ({ isOpen, onClose, song }) => {
|
|||||||
const favorites = useAppSelector(selectFavorites);
|
const favorites = useAppSelector(selectFavorites);
|
||||||
const allSongs = useAppSelector(selectSongs);
|
const allSongs = useAppSelector(selectSongs);
|
||||||
const queue = useAppSelector(selectQueue);
|
const queue = useAppSelector(selectQueue);
|
||||||
const { handleToggleFavorite, handleToggleDisabled, isSongDisabled } = useActionHandlers();
|
const { handleToggleFavorite, handleToggleDisabled, isSongDisabled } = useActions();
|
||||||
|
|
||||||
const { openSelectSinger } = useModal();
|
const { openSelectSinger } = useModal();
|
||||||
const [showArtistSongs, setShowArtistSongs] = useState(false);
|
const [showArtistSongs, setShowArtistSongs] = useState(false);
|
||||||
|
|||||||
@ -3,8 +3,7 @@ import { IonItem, IonLabel } from '@ionic/react';
|
|||||||
import ActionButton from './ActionButton';
|
import ActionButton from './ActionButton';
|
||||||
import { useAppSelector } from '../../redux';
|
import { useAppSelector } from '../../redux';
|
||||||
import { selectQueue, selectFavorites } from '../../redux';
|
import { selectQueue, selectFavorites } from '../../redux';
|
||||||
import { useSongOperations } from '../../hooks/useSongOperations';
|
import { useActions } from '../../hooks/useActions';
|
||||||
import { useToast } from '../../hooks/useToast';
|
|
||||||
import { useModal } from '../../hooks/useModalContext';
|
import { useModal } from '../../hooks/useModalContext';
|
||||||
import { debugLog } from '../../utils/logger';
|
import { debugLog } from '../../utils/logger';
|
||||||
import type { SongItemProps, QueueItem, Song } from '../../types';
|
import type { SongItemProps, QueueItem, Song } from '../../types';
|
||||||
@ -214,9 +213,8 @@ const SongItem: React.FC<SongItemProps> = ({
|
|||||||
const queue = useAppSelector(selectQueue);
|
const queue = useAppSelector(selectQueue);
|
||||||
const favorites = useAppSelector(selectFavorites);
|
const favorites = useAppSelector(selectFavorites);
|
||||||
|
|
||||||
// Get song operations and hooks
|
// Get unified action handlers
|
||||||
const { addToQueue, removeFromQueue, toggleFavorite } = useSongOperations();
|
const { handleAddToQueue, handleToggleFavorite, handleRemoveFromQueue } = useActions();
|
||||||
const { showSuccess, showError } = useToast();
|
|
||||||
const { openSongInfo } = useModal();
|
const { openSongInfo } = useModal();
|
||||||
|
|
||||||
// Check if song is in queue or favorites based on path
|
// Check if song is in queue or favorites based on path
|
||||||
@ -248,33 +246,21 @@ const SongItem: React.FC<SongItemProps> = ({
|
|||||||
const shouldShowDeleteButton = showDeleteButton !== undefined ? showDeleteButton : context === 'history' && isAdmin;
|
const shouldShowDeleteButton = showDeleteButton !== undefined ? showDeleteButton : context === 'history' && isAdmin;
|
||||||
const shouldShowFavoriteButton = showFavoriteButton !== undefined ? showFavoriteButton : false; // Disabled for all contexts
|
const shouldShowFavoriteButton = showFavoriteButton !== undefined ? showFavoriteButton : false; // Disabled for all contexts
|
||||||
|
|
||||||
// Handle song operations internally
|
// Create wrapper functions for the unified handlers
|
||||||
const handleAddToQueue = async () => {
|
const handleAddToQueueClick = async () => {
|
||||||
try {
|
await handleAddToQueue(song);
|
||||||
await addToQueue(song);
|
|
||||||
showSuccess('Song added to queue');
|
|
||||||
} catch {
|
|
||||||
showError('Failed to add song to queue');
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveFromQueue = async () => {
|
const handleToggleFavoriteClick = async () => {
|
||||||
|
await handleToggleFavorite(song);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemoveFromQueueClick = async () => {
|
||||||
if (!queueItemKey) return;
|
if (!queueItemKey) return;
|
||||||
|
// Find the queue item by key
|
||||||
try {
|
const queueItem = (Object.values(queue) as QueueItem[]).find(item => item.key === queueItemKey);
|
||||||
await removeFromQueue(queueItemKey);
|
if (queueItem) {
|
||||||
showSuccess('Song removed from queue');
|
await handleRemoveFromQueue(queueItem);
|
||||||
} catch {
|
|
||||||
showError('Failed to remove song from queue');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleToggleFavorite = async () => {
|
|
||||||
try {
|
|
||||||
await toggleFavorite(song);
|
|
||||||
showSuccess(isInFavorites ? 'Removed from favorites' : 'Added to favorites');
|
|
||||||
} catch {
|
|
||||||
showError('Failed to update favorites');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -302,9 +288,9 @@ const SongItem: React.FC<SongItemProps> = ({
|
|||||||
showDeleteButton={shouldShowDeleteButton}
|
showDeleteButton={shouldShowDeleteButton}
|
||||||
showFavoriteButton={shouldShowFavoriteButton}
|
showFavoriteButton={shouldShowFavoriteButton}
|
||||||
onDeleteItem={onDeleteItem}
|
onDeleteItem={onDeleteItem}
|
||||||
onAddToQueue={context === 'queue' ? handleRemoveFromQueue : handleAddToQueue}
|
onAddToQueue={context === 'queue' ? handleRemoveFromQueueClick : handleAddToQueueClick}
|
||||||
onRemoveFromQueue={context === 'queue' ? handleRemoveFromQueue : onDeleteItem}
|
onRemoveFromQueue={context === 'queue' ? handleRemoveFromQueueClick : onDeleteItem}
|
||||||
onToggleFavorite={context === 'favorites' ? onDeleteItem : handleToggleFavorite}
|
onToggleFavorite={context === 'favorites' ? onDeleteItem : handleToggleFavoriteClick}
|
||||||
onShowSongInfo={handleSelectSinger}
|
onShowSongInfo={handleSelectSinger}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,48 +1,43 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { IonItem, IonLabel, IonItemSliding, IonItemOptions, IonItemOption, IonIcon, IonReorderGroup, IonReorder } from '@ionic/react';
|
import { IonItem, IonLabel, IonItemSliding, IonItemOptions, IonItemOption, IonIcon, IonReorderGroup, IonReorder } from '@ionic/react';
|
||||||
import { reorderThreeOutline, reorderTwoOutline, list } from 'ionicons/icons';
|
import { reorderThreeOutline, reorderTwoOutline, list } from 'ionicons/icons';
|
||||||
import { useQueue } from '../../hooks';
|
import { useQueue, useActions } from '../../hooks';
|
||||||
import { useAppSelector } from '../../redux';
|
import { useAppSelector } from '../../redux';
|
||||||
import { selectQueueLength, selectPlayerStateMemoized, selectIsAdmin, selectControllerName } from '../../redux';
|
import { selectQueueLength } from '../../redux';
|
||||||
import { ActionButton, NumberDisplay, EmptyState } from '../../components/common';
|
import { ActionButton, NumberDisplay, EmptyState } from '../../components/common';
|
||||||
import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types';
|
import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types';
|
||||||
import { Icons } from '../../constants';
|
import { Icons } from '../../constants';
|
||||||
import { SongInfoDisplay } from '../../components/common/SongItem';
|
import { SongInfoDisplay } from '../../components/common/SongItem';
|
||||||
import { queueService } from '../../firebase/services';
|
|
||||||
import { debugLog } from '../../utils/logger';
|
import { debugLog } from '../../utils/logger';
|
||||||
import { PlayerState } from '../../types';
|
|
||||||
import type { QueueItem } from '../../types';
|
import type { QueueItem } from '../../types';
|
||||||
|
|
||||||
type QueueMode = 'delete' | 'reorder';
|
|
||||||
|
|
||||||
const Queue: React.FC = () => {
|
const Queue: React.FC = () => {
|
||||||
const [queueMode, setQueueMode] = useState<QueueMode>('delete');
|
|
||||||
const [listItems, setListItems] = useState<QueueItem[]>([]);
|
const [listItems, setListItems] = useState<QueueItem[]>([]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
queueItems,
|
queueItems,
|
||||||
canReorder,
|
|
||||||
handleRemoveFromQueue,
|
handleRemoveFromQueue,
|
||||||
} = useQueue();
|
} = useQueue();
|
||||||
|
|
||||||
|
const {
|
||||||
|
queueMode,
|
||||||
|
canDeleteItems,
|
||||||
|
canDeleteFirstItem,
|
||||||
|
toggleQueueMode,
|
||||||
|
handleReorder,
|
||||||
|
} = useActions();
|
||||||
|
|
||||||
|
// Check if reordering is allowed
|
||||||
|
const canReorder = canDeleteItems && queueItems.length > 1;
|
||||||
|
|
||||||
const queueCount = useAppSelector(selectQueueLength);
|
const queueCount = useAppSelector(selectQueueLength);
|
||||||
const playerState = useAppSelector(selectPlayerStateMemoized);
|
|
||||||
const isAdmin = useAppSelector(selectIsAdmin);
|
|
||||||
const controllerName = useAppSelector(selectControllerName);
|
|
||||||
|
|
||||||
// Debug logging
|
// Debug logging
|
||||||
debugLog('Queue component - queue count:', queueCount);
|
debugLog('Queue component - queue count:', queueCount);
|
||||||
debugLog('Queue component - queue items:', queueItems);
|
debugLog('Queue component - queue items:', queueItems);
|
||||||
debugLog('Queue component - player state:', playerState);
|
|
||||||
debugLog('Queue component - isAdmin:', isAdmin);
|
|
||||||
debugLog('Queue component - canReorder:', canReorder);
|
debugLog('Queue component - canReorder:', canReorder);
|
||||||
debugLog('Queue component - queueMode:', queueMode);
|
debugLog('Queue component - queueMode:', queueMode);
|
||||||
|
|
||||||
// Check if items can be deleted (admin can delete any item when not playing)
|
|
||||||
const canDeleteItems = isAdmin && (playerState?.state === PlayerState.stopped || playerState?.state === PlayerState.paused);
|
|
||||||
|
|
||||||
debugLog('Queue component - canDeleteItems:', canDeleteItems);
|
debugLog('Queue component - canDeleteItems:', canDeleteItems);
|
||||||
debugLog('Queue component - canReorder:', canReorder);
|
|
||||||
|
|
||||||
|
|
||||||
// Update list items when queue changes
|
// Update list items when queue changes
|
||||||
@ -55,52 +50,15 @@ const Queue: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}, [queueItems]);
|
}, [queueItems]);
|
||||||
|
|
||||||
// Toggle between modes
|
|
||||||
const toggleQueueMode = () => {
|
|
||||||
setQueueMode(prevMode => prevMode === 'delete' ? 'reorder' : 'delete');
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle reorder event from IonReorderGroup
|
// Handle reorder event from IonReorderGroup
|
||||||
const doReorder = async (event: CustomEvent) => {
|
const doReorder = async (event: CustomEvent) => {
|
||||||
debugLog('Reorder event:', event.detail);
|
await handleReorder(event, queueItems);
|
||||||
const { from, to, complete } = event.detail;
|
|
||||||
|
|
||||||
if (listItems && controllerName) {
|
|
||||||
const copy = [...listItems];
|
|
||||||
const draggedItem = copy.splice(from, 1)[0];
|
|
||||||
copy.splice(to, 0, draggedItem);
|
|
||||||
|
|
||||||
// Complete the reorder animation
|
|
||||||
complete();
|
|
||||||
|
|
||||||
// Create the new queue order (first item + reordered items)
|
|
||||||
const newQueueItems = [queueItems[0], ...copy];
|
|
||||||
debugLog('New queue order:', newQueueItems);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Update all items with their new order values
|
|
||||||
const updatePromises = newQueueItems.map((item, index) => {
|
|
||||||
const newOrder = index + 1;
|
|
||||||
if (item.key && item.order !== newOrder) {
|
|
||||||
debugLog(`Updating item ${item.key} from order ${item.order} to ${newOrder}`);
|
|
||||||
return queueService.updateQueueItem(controllerName, item.key, { order: newOrder });
|
|
||||||
}
|
|
||||||
return Promise.resolve();
|
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.all(updatePromises);
|
|
||||||
debugLog('Queue reorder completed successfully');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to reorder queue:', error);
|
|
||||||
// You might want to show an error toast here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Render queue item
|
// Render queue item
|
||||||
const renderQueueItem = (queueItem: QueueItem, index: number) => {
|
const renderQueueItem = (queueItem: QueueItem, index: number) => {
|
||||||
debugLog(`Queue item ${index}: order=${queueItem.order}, key=${queueItem.key}`);
|
debugLog(`Queue item ${index}: order=${queueItem.order}, key=${queueItem.key}`);
|
||||||
const canDelete = isAdmin && queueMode === 'delete'; // Only allow delete in delete mode
|
const canDelete = canDeleteItems && queueMode === 'delete'; // Only allow delete in delete mode
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IonItemSliding key={queueItem.key}>
|
<IonItemSliding key={queueItem.key}>
|
||||||
@ -167,7 +125,6 @@ const Queue: React.FC = () => {
|
|||||||
if (queueItems.length === 0) return null;
|
if (queueItems.length === 0) return null;
|
||||||
|
|
||||||
const firstItem = queueItems[0];
|
const firstItem = queueItems[0];
|
||||||
const canDeleteFirstItem = isAdmin && (playerState?.state === PlayerState.stopped || playerState?.state === PlayerState.paused);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<IonItemSliding key={firstItem.key}>
|
<IonItemSliding key={firstItem.key}>
|
||||||
@ -236,7 +193,7 @@ const Queue: React.FC = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="ion-padding">
|
<div className="ion-padding">
|
||||||
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: '1rem' }}>
|
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: '1rem' }}>
|
||||||
{isAdmin && (
|
{canDeleteItems && (
|
||||||
<ActionButton
|
<ActionButton
|
||||||
onClick={toggleQueueMode}
|
onClick={toggleQueueMode}
|
||||||
variant={ActionButtonVariant.SECONDARY}
|
variant={ActionButtonVariant.SECONDARY}
|
||||||
|
|||||||
@ -11,6 +11,6 @@ export { useArtists } from './useArtists';
|
|||||||
export { useSingers } from './useSingers';
|
export { useSingers } from './useSingers';
|
||||||
export { useSongLists } from './useSongLists';
|
export { useSongLists } from './useSongLists';
|
||||||
export { useDisabledSongs } from './useDisabledSongs';
|
export { useDisabledSongs } from './useDisabledSongs';
|
||||||
export { useActionHandlers } from './useActionHandlers';
|
export { useActions } from './useActions';
|
||||||
|
|
||||||
export { useSongInfo } from './useSongInfo';
|
export { useSongInfo } from './useSongInfo';
|
||||||
@ -1,69 +0,0 @@
|
|||||||
import { useCallback } from 'react';
|
|
||||||
import { useSongOperations } from './useSongOperations';
|
|
||||||
import { useToast } from './useToast';
|
|
||||||
import { useDisabledSongs } from './useDisabledSongs';
|
|
||||||
import { historyService } from '../firebase/services';
|
|
||||||
import { useAppSelector } from '../redux';
|
|
||||||
import { selectControllerName } from '../redux';
|
|
||||||
import type { Song } from '../types';
|
|
||||||
|
|
||||||
export const useActionHandlers = () => {
|
|
||||||
const { addToQueue, toggleFavorite } = useSongOperations();
|
|
||||||
const { showSuccess, showError } = useToast();
|
|
||||||
const { isSongDisabled, addDisabledSong, removeDisabledSong } = useDisabledSongs();
|
|
||||||
const controllerName = useAppSelector(selectControllerName);
|
|
||||||
|
|
||||||
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);
|
|
||||||
showSuccess('Song enabled');
|
|
||||||
} else {
|
|
||||||
await addDisabledSong(song);
|
|
||||||
showSuccess('Song disabled');
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
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');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await historyService.removeFromHistory(controllerName, song.key);
|
|
||||||
showSuccess('Removed from history');
|
|
||||||
} catch {
|
|
||||||
showError('Failed to remove from history');
|
|
||||||
}
|
|
||||||
}, [controllerName, showSuccess, showError]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
handleAddToQueue,
|
|
||||||
handleToggleFavorite,
|
|
||||||
handleToggleDisabled,
|
|
||||||
handleDeleteFromHistory,
|
|
||||||
isSongDisabled,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
153
src/hooks/useActions.ts
Normal file
153
src/hooks/useActions.ts
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
import { useState, useCallback } from 'react';
|
||||||
|
import { useAppSelector } from '../redux';
|
||||||
|
import { selectControllerName, selectPlayerStateMemoized, selectIsAdmin } from '../redux';
|
||||||
|
import { useSongOperations } from './useSongOperations';
|
||||||
|
import { useToast } from './useToast';
|
||||||
|
import { useDisabledSongs } from './useDisabledSongs';
|
||||||
|
import { queueService, historyService } from '../firebase/services';
|
||||||
|
import { debugLog } from '../utils/logger';
|
||||||
|
import { PlayerState } from '../types';
|
||||||
|
import type { Song, QueueItem } from '../types';
|
||||||
|
|
||||||
|
export type QueueMode = 'delete' | 'reorder';
|
||||||
|
|
||||||
|
export const useActions = () => {
|
||||||
|
const [queueMode, setQueueMode] = useState<QueueMode>('delete');
|
||||||
|
|
||||||
|
const controllerName = useAppSelector(selectControllerName);
|
||||||
|
const playerState = useAppSelector(selectPlayerStateMemoized);
|
||||||
|
const isAdmin = useAppSelector(selectIsAdmin);
|
||||||
|
const { addToQueue, removeFromQueue, toggleFavorite } = useSongOperations();
|
||||||
|
const { showSuccess, showError } = useToast();
|
||||||
|
const { isSongDisabled, addDisabledSong, removeDisabledSong } = useDisabledSongs();
|
||||||
|
|
||||||
|
// Queue permissions
|
||||||
|
const canDeleteItems = isAdmin && (playerState?.state === PlayerState.stopped || playerState?.state === PlayerState.paused);
|
||||||
|
const canDeleteFirstItem = isAdmin && (playerState?.state === PlayerState.stopped || playerState?.state === PlayerState.paused);
|
||||||
|
|
||||||
|
// Song operations
|
||||||
|
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 handleRemoveFromQueue = useCallback(async (queueItem: QueueItem) => {
|
||||||
|
if (!queueItem.key) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await removeFromQueue(queueItem.key);
|
||||||
|
showSuccess('Song removed from queue');
|
||||||
|
} catch {
|
||||||
|
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');
|
||||||
|
} catch {
|
||||||
|
showError('Failed to update favorites');
|
||||||
|
}
|
||||||
|
}, [toggleFavorite, showSuccess, showError]);
|
||||||
|
|
||||||
|
const handleToggleDisabled = useCallback(async (song: Song) => {
|
||||||
|
try {
|
||||||
|
if (isSongDisabled(song)) {
|
||||||
|
await removeDisabledSong(song);
|
||||||
|
showSuccess('Song enabled');
|
||||||
|
} else {
|
||||||
|
await addDisabledSong(song);
|
||||||
|
showSuccess('Song disabled');
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
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');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await historyService.removeFromHistory(controllerName, song.key);
|
||||||
|
showSuccess('Removed from history');
|
||||||
|
} catch {
|
||||||
|
showError('Failed to remove from history');
|
||||||
|
}
|
||||||
|
}, [controllerName, showSuccess, showError]);
|
||||||
|
|
||||||
|
// Queue UI operations
|
||||||
|
const toggleQueueMode = useCallback(() => {
|
||||||
|
setQueueMode(prevMode => prevMode === 'delete' ? 'reorder' : 'delete');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Queue operations
|
||||||
|
const handleReorder = useCallback(async (event: CustomEvent, queueItems: QueueItem[]) => {
|
||||||
|
debugLog('Reorder event:', event.detail);
|
||||||
|
const { from, to, complete } = event.detail;
|
||||||
|
|
||||||
|
if (!controllerName) {
|
||||||
|
showError('Cannot reorder - controller not available');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create the new queue order (first item + reordered items)
|
||||||
|
const listItems = queueItems.slice(1); // Skip first item for reordering
|
||||||
|
const copy = [...listItems];
|
||||||
|
const draggedItem = copy.splice(from, 1)[0];
|
||||||
|
copy.splice(to, 0, draggedItem);
|
||||||
|
|
||||||
|
// Complete the reorder animation
|
||||||
|
complete();
|
||||||
|
|
||||||
|
const newQueueItems = [queueItems[0], ...copy];
|
||||||
|
debugLog('New queue order:', newQueueItems);
|
||||||
|
|
||||||
|
// Update all items with their new order values
|
||||||
|
const updatePromises = newQueueItems.map((item, index) => {
|
||||||
|
const newOrder = index + 1;
|
||||||
|
if (item.key && item.order !== newOrder) {
|
||||||
|
debugLog(`Updating item ${item.key} from order ${item.order} to ${newOrder}`);
|
||||||
|
return queueService.updateQueueItem(controllerName, item.key, { order: newOrder });
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(updatePromises);
|
||||||
|
debugLog('Queue reorder completed successfully');
|
||||||
|
showSuccess('Queue reordered successfully');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to reorder queue:', error);
|
||||||
|
showError('Failed to reorder queue');
|
||||||
|
}
|
||||||
|
}, [controllerName, showSuccess, showError]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
// Song operations
|
||||||
|
handleAddToQueue,
|
||||||
|
handleRemoveFromQueue,
|
||||||
|
handleToggleFavorite,
|
||||||
|
handleToggleDisabled,
|
||||||
|
handleDeleteFromHistory,
|
||||||
|
|
||||||
|
// Queue UI state
|
||||||
|
queueMode,
|
||||||
|
toggleQueueMode,
|
||||||
|
|
||||||
|
// Queue operations
|
||||||
|
handleReorder,
|
||||||
|
|
||||||
|
// Permissions
|
||||||
|
canDeleteItems,
|
||||||
|
canDeleteFirstItem,
|
||||||
|
isSongDisabled,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,14 +1,14 @@
|
|||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
import { useAppSelector, selectFavoritesArray } from '../redux';
|
import { useAppSelector, selectFavoritesArray } from '../redux';
|
||||||
import { debugLog } from '../utils/logger';
|
import { debugLog } from '../utils/logger';
|
||||||
import { useActionHandlers } from './useActionHandlers';
|
import { useActions } from './useActions';
|
||||||
import { useDisabledSongs } from './useDisabledSongs';
|
import { useDisabledSongs } from './useDisabledSongs';
|
||||||
|
|
||||||
const ITEMS_PER_PAGE = 20;
|
const ITEMS_PER_PAGE = 20;
|
||||||
|
|
||||||
export const useFavorites = () => {
|
export const useFavorites = () => {
|
||||||
const allFavoritesItems = useAppSelector(selectFavoritesArray);
|
const allFavoritesItems = useAppSelector(selectFavoritesArray);
|
||||||
const { handleAddToQueue, handleToggleFavorite, handleToggleDisabled, isSongDisabled } = useActionHandlers();
|
const { handleAddToQueue, handleToggleFavorite, handleToggleDisabled, isSongDisabled } = useActions();
|
||||||
const { disabledSongPaths, loading: disabledSongsLoading } = useDisabledSongs();
|
const { disabledSongPaths, loading: disabledSongsLoading } = useDisabledSongs();
|
||||||
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
import { useAppSelector, selectHistoryArray } from '../redux';
|
import { useAppSelector, selectHistoryArray } from '../redux';
|
||||||
import { debugLog } from '../utils/logger';
|
import { debugLog } from '../utils/logger';
|
||||||
import { useActionHandlers } from './useActionHandlers';
|
import { useActions } from './useActions';
|
||||||
import { useDisabledSongs } from './useDisabledSongs';
|
import { useDisabledSongs } from './useDisabledSongs';
|
||||||
|
|
||||||
const ITEMS_PER_PAGE = 20;
|
const ITEMS_PER_PAGE = 20;
|
||||||
|
|
||||||
export const useHistory = () => {
|
export const useHistory = () => {
|
||||||
const allHistoryItems = useAppSelector(selectHistoryArray);
|
const allHistoryItems = useAppSelector(selectHistoryArray);
|
||||||
const { handleAddToQueue, handleToggleFavorite, handleToggleDisabled, handleDeleteFromHistory, isSongDisabled } = useActionHandlers();
|
const { handleAddToQueue, handleToggleFavorite, handleToggleDisabled, handleDeleteFromHistory, isSongDisabled } = useActions();
|
||||||
const { disabledSongPaths, loading: disabledSongsLoading } = useDisabledSongs();
|
const { disabledSongPaths, loading: disabledSongsLoading } = useDisabledSongs();
|
||||||
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useState, useCallback, useMemo } from 'react';
|
import { useState, useCallback, useMemo } from 'react';
|
||||||
import { useAppSelector, selectSongsArray } from '../redux';
|
import { useAppSelector, selectSongsArray } from '../redux';
|
||||||
import { useActionHandlers } from './useActionHandlers';
|
import { useActions } from './useActions';
|
||||||
import { useDisabledSongs } from './useDisabledSongs';
|
import { useDisabledSongs } from './useDisabledSongs';
|
||||||
import { UI_CONSTANTS } from '../constants';
|
import { UI_CONSTANTS } from '../constants';
|
||||||
import { filterSongs } from '../utils/dataProcessing';
|
import { filterSongs } from '../utils/dataProcessing';
|
||||||
@ -11,7 +11,7 @@ const ITEMS_PER_PAGE = 20;
|
|||||||
export const useSearch = () => {
|
export const useSearch = () => {
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const { handleAddToQueue, handleToggleFavorite, handleToggleDisabled, isSongDisabled } = useActionHandlers();
|
const { handleAddToQueue, handleToggleFavorite, handleToggleDisabled, isSongDisabled } = useActions();
|
||||||
const { disabledSongPaths, loading: disabledSongsLoading } = useDisabledSongs();
|
const { disabledSongPaths, loading: disabledSongsLoading } = useDisabledSongs();
|
||||||
|
|
||||||
// Get all songs from Redux (this is memoized)
|
// Get all songs from Redux (this is memoized)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user