import React, { useState } from 'react'; import { IonContent, IonHeader, IonTitle, IonToolbar, IonList, IonItem, IonLabel, IonToggle, IonButton, IonIcon, IonModal, IonSearchbar } from '@ionic/react'; import { ban } from 'ionicons/icons'; import { useAppSelector } from '../../redux'; import { selectIsAdmin, selectSettings, updateController, selectControllerName } from '../../redux'; import { useDispatch } from 'react-redux'; import { useDisabledSongs } from '../../hooks'; import { InfiniteScrollList, ActionButton, SongItem } from '../../components/common'; import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types'; 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); const playerSettings = useAppSelector(selectSettings); const dispatch = useDispatch(); const { disabledSongs, loading, removeDisabledSong } = useDisabledSongs(); const [showDisabledSongsModal, setShowDisabledSongsModal] = useState(false); const [searchTerm, setSearchTerm] = useState(''); const controllerNameRedux = useAppSelector(selectControllerName); 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]) => ({ key: disabledSong.key || key, path: disabledSong.path, artist: disabledSong.artist, title: disabledSong.title, disabledAt: disabledSong.disabledAt, })); // Filter disabled songs by search term const filteredDisabledSongs: DisabledSong[] = searchTerm.trim() ? filterSongs(disabledSongsArray, searchTerm) as DisabledSong[] : disabledSongsArray; const handleToggleSetting = async (setting: string, value: boolean) => { debugLog(`Toggle ${setting} to ${value}`); const controllerName = controllerNameRedux; if (controllerName) { // @ts-expect-error: Redux Thunk type mismatch workaround dispatch(updateController({ controllerName, updates: { player: { queue: updatedPlayer.queue, settings: { ...updatedPlayer.settings, [setting]: value }, singers: updatedPlayer.singers, state: updatedPlayer.state, } } })); } }; const handleToggleDebug = (enabled: boolean) => { setDebugEnabled(enabled); }; const handleRemoveDisabledSong = async (song: DisabledSong) => { // Create a minimal song object with the path for removal const songForRemoval: Song = { path: song.path, artist: song.artist, title: song.title, key: song.key, }; await removeDisabledSong(songForRemoval); }; if (!isAdmin) { return (

Admin access required to view settings.

); } return ( <>
{/* Player Settings */}

Player Settings

Auto Advance handleToggleSetting('autoadvance', e.detail.checked)} /> User Pick handleToggleSetting('userpick', e.detail.checked)} /> Show Toasts handleToggleSetting('showToasts', e.detail.checked)} /> Debug Logging handleToggleDebug(e.detail.checked)} />
{/* Disabled Songs Management */}

Disabled Songs Management

setShowDisabledSongsModal(true)} disabled={loading} > Manage Disabled Songs ({disabledSongsArray.length})

Songs marked as disabled will be hidden from search results, favorites, and other song lists.

Use the search page to mark individual songs as disabled, or manage all disabled songs here.

{/* Disabled Songs Modal */} setShowDisabledSongsModal(false)} breakpoints={[0, 0.5, 0.8]} initialBreakpoint={0.8} > Disabled Songs ({filteredDisabledSongs.length})
setShowDisabledSongsModal(false)} variant={ActionButtonVariant.SECONDARY} size={ActionButtonSize.SMALL} icon={Icons.CLOSE} iconSlot={ActionButtonIconSlot.ICON_ONLY} fill="clear" />
{/* Search */} setSearchTerm(e.detail.value || '')} debounce={300} showClearButton="focus" />
{/* Disabled Songs List */} items={filteredDisabledSongs} isLoading={loading} hasMore={false} onLoadMore={() => {}} renderItem={(song) => (
handleRemoveDisabledSong(song)} showFullPath={true} />
{/* Delete button is now handled by SongItem */}
)} emptyTitle="No disabled songs" emptyMessage="Songs marked as disabled will appear here" loadingTitle="Loading disabled songs..." loadingMessage="Please wait while disabled songs are being loaded" />
); }; export default Settings;