Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>

This commit is contained in:
Matt Bruce 2025-07-18 16:53:43 -05:00
parent 3e143dade9
commit bdb57f46ed
25 changed files with 169 additions and 97 deletions

View File

@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom'; import { useSearchParams } from 'react-router-dom';
import { useAppDispatch, useAppSelector } from '../../redux/hooks'; import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import { selectIsAuthenticated } from '../../redux/authSlice'; import { selectIsAuthenticated } from '../../redux/authSlice';
import { debugLog } from '../../utils/logger';
import { LoginPrompt } from './index'; import { LoginPrompt } from './index';
interface AuthInitializerProps { interface AuthInitializerProps {
@ -17,7 +18,7 @@ const AuthInitializer: React.FC<AuthInitializerProps> = ({ children }) => {
const isAuthenticated = useAppSelector(selectIsAuthenticated); const isAuthenticated = useAppSelector(selectIsAuthenticated);
useEffect(() => { useEffect(() => {
console.log('AuthInitializer effect - isAuthenticated:', isAuthenticated, 'showLogin:', showLogin); debugLog('AuthInitializer effect - isAuthenticated:', isAuthenticated, 'showLogin:', showLogin);
// Only process admin parameter once // Only process admin parameter once
if (hasProcessedAdminParam) return; if (hasProcessedAdminParam) return;
@ -54,7 +55,7 @@ const AuthInitializer: React.FC<AuthInitializerProps> = ({ children }) => {
<LoginPrompt <LoginPrompt
isAdmin={isAdminMode} isAdmin={isAdminMode}
onComplete={() => { onComplete={() => {
console.log('onComplete called, setting showLogin to false'); debugLog('onComplete called, setting showLogin to false');
setShowLogin(false); setShowLogin(false);
}} }}
/> />

View File

@ -2,6 +2,7 @@ import { useState } from 'react';
import { IonIcon } from '@ionic/react'; import { IonIcon } from '@ionic/react';
import { micOutline } from 'ionicons/icons'; import { micOutline } from 'ionicons/icons';
import { useAppDispatch } from '../../redux/hooks'; import { useAppDispatch } from '../../redux/hooks';
import { debugLog } from '../../utils/logger';
import { setAuth } from '../../redux/authSlice'; import { setAuth } from '../../redux/authSlice';
import { database } from '../../firebase/config'; import { database } from '../../firebase/config';
import { ref, get } from 'firebase/database'; import { ref, get } from 'firebase/database';
@ -20,7 +21,7 @@ const LoginPrompt: React.FC<LoginPromptProps> = ({ isAdmin, onComplete }) => {
const handleSubmit = async (e: React.FormEvent) => { const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
console.log('Login form submitted'); debugLog('Login form submitted');
if (!partyId.trim() || !singerName.trim()) { if (!partyId.trim() || !singerName.trim()) {
setError('Please enter both Party Id and your name.'); setError('Please enter both Party Id and your name.');
return; return;
@ -43,9 +44,9 @@ const LoginPrompt: React.FC<LoginPromptProps> = ({ isAdmin, onComplete }) => {
isAdmin: isAdmin, isAdmin: isAdmin,
controller: partyId.trim(), controller: partyId.trim(),
}; };
console.log('Dispatching auth:', auth); debugLog('Dispatching auth:', auth);
dispatch(setAuth(auth)); dispatch(setAuth(auth));
console.log('Calling onComplete'); debugLog('Calling onComplete');
onComplete(); onComplete();
} catch (error) { } catch (error) {
console.error('Error checking controller:', error); console.error('Error checking controller:', error);

View File

@ -5,6 +5,7 @@ import { useLocation, useNavigate } from 'react-router-dom';
import { PlayerControls } from '../common'; import { PlayerControls } from '../common';
import { useAppSelector } from '../../redux'; import { useAppSelector } from '../../redux';
import { selectIsAdmin } from '../../redux'; import { selectIsAdmin } from '../../redux';
import { debugLog } from '../../utils/logger';
const Navigation: React.FC = () => { const Navigation: React.FC = () => {
const location = useLocation(); const location = useLocation();
@ -32,7 +33,7 @@ const Navigation: React.FC = () => {
useEffect(() => { useEffect(() => {
const checkScreenSize = () => { const checkScreenSize = () => {
const large = window.innerWidth >= 768; const large = window.innerWidth >= 768;
console.log('Screen width:', window.innerWidth, 'Is large screen:', large); debugLog('Screen width:', window.innerWidth, 'Is large screen:', large);
setIsLargeScreen(large); setIsLargeScreen(large);
}; };
@ -54,7 +55,7 @@ const Navigation: React.FC = () => {
// For large screens, render a fixed sidebar instead of a menu // For large screens, render a fixed sidebar instead of a menu
if (isLargeScreen) { if (isLargeScreen) {
console.log('Rendering large screen sidebar'); debugLog('Rendering large screen sidebar');
return ( return (
<div <div
style={{ style={{
@ -121,7 +122,7 @@ const Navigation: React.FC = () => {
} }
// For mobile screens, use the Ionic menu // For mobile screens, use the Ionic menu
console.log('Rendering mobile menu'); debugLog('Rendering mobile menu');
return ( return (
<IonMenu <IonMenu
contentId="main-content" contentId="main-content"

View File

@ -1,4 +1,5 @@
import React, { useEffect, useRef } from 'react'; import React, { useEffect, useRef } from 'react';
import { debugLog } from '../../utils/logger';
import { EmptyState } from './index'; import { EmptyState } from './index';
interface InfiniteScrollListProps<T> { interface InfiniteScrollListProps<T> {
@ -28,18 +29,18 @@ const InfiniteScrollList = <T extends string | { key?: string }>({
// Intersection Observer for infinite scrolling // Intersection Observer for infinite scrolling
useEffect(() => { useEffect(() => {
console.log('InfiniteScrollList - Setting up observer:', { hasMore, isLoading, itemsLength: items.length }); debugLog('InfiniteScrollList - Setting up observer:', { hasMore, isLoading, itemsLength: items.length });
const observer = new IntersectionObserver( const observer = new IntersectionObserver(
(entries) => { (entries) => {
console.log('InfiniteScrollList - Intersection detected:', { debugLog('InfiniteScrollList - Intersection detected:', {
isIntersecting: entries[0].isIntersecting, isIntersecting: entries[0].isIntersecting,
hasMore, hasMore,
isLoading isLoading
}); });
if (entries[0].isIntersecting && hasMore && !isLoading) { if (entries[0].isIntersecting && hasMore && !isLoading) {
console.log('InfiniteScrollList - Loading more items'); debugLog('InfiniteScrollList - Loading more items');
onLoadMore(); onLoadMore();
} }
}, },

View File

@ -6,6 +6,7 @@ import { useAppSelector } from '../../redux';
import { selectPlayerState, selectIsAdmin, selectQueue } from '../../redux'; import { selectPlayerState, selectIsAdmin, selectQueue } from '../../redux';
import { playerService } from '../../firebase/services'; import { playerService } from '../../firebase/services';
import { selectControllerName } from '../../redux'; import { selectControllerName } from '../../redux';
import { debugLog } from '../../utils/logger';
import { useToast } from '../../hooks/useToast'; import { useToast } from '../../hooks/useToast';
import { PlayerState } from '../../types'; import { PlayerState } from '../../types';
@ -22,9 +23,9 @@ const PlayerControls: React.FC<PlayerControlsProps> = ({ className = '', variant
const { showSuccess, showError } = useToast(); const { showSuccess, showError } = useToast();
// Debug logging // Debug logging
console.log('PlayerControls - playerState:', playerState); debugLog('PlayerControls - playerState:', playerState);
console.log('PlayerControls - isAdmin:', isAdmin); debugLog('PlayerControls - isAdmin:', isAdmin);
console.log('PlayerControls - queue length:', Object.keys(queue).length); debugLog('PlayerControls - queue length:', Object.keys(queue).length);
const handlePlay = async () => { const handlePlay = async () => {
if (!controllerName) return; if (!controllerName) return;
@ -70,8 +71,8 @@ const PlayerControls: React.FC<PlayerControlsProps> = ({ className = '', variant
const currentState = playerState?.state || PlayerState.stopped; const currentState = playerState?.state || PlayerState.stopped;
const hasSongsInQueue = Object.keys(queue).length > 0; const hasSongsInQueue = Object.keys(queue).length > 0;
console.log('PlayerControls - currentState:', currentState); debugLog('PlayerControls - currentState:', currentState);
console.log('PlayerControls - hasSongsInQueue:', hasSongsInQueue); debugLog('PlayerControls - hasSongsInQueue:', hasSongsInQueue);
const getStateColor = () => { const getStateColor = () => {
switch (currentState) { switch (currentState) {

View File

@ -5,6 +5,7 @@ import { InfiniteScrollList, SongItem } from '../../components/common';
import { useArtists } from '../../hooks'; import { useArtists } from '../../hooks';
import { useAppSelector } from '../../redux'; import { useAppSelector } from '../../redux';
import { selectSongs } from '../../redux'; import { selectSongs } from '../../redux';
import { debugLog } from '../../utils/logger';
const Artists: React.FC = () => { const Artists: React.FC = () => {
const { const {
@ -24,10 +25,10 @@ const Artists: React.FC = () => {
const [selectedArtist, setSelectedArtist] = useState<string | null>(null); const [selectedArtist, setSelectedArtist] = useState<string | null>(null);
// Debug logging // Debug logging
console.log('Artists component - artists count:', artists.length); debugLog('Artists component - artists count:', artists.length);
console.log('Artists component - selected artist:', selectedArtist); debugLog('Artists component - selected artist:', selectedArtist);
console.log('Artists component - songs count:', songsCount); debugLog('Artists component - songs count:', songsCount);
console.log('Artists component - search term:', searchTerm); debugLog('Artists component - search term:', searchTerm);
const handleArtistClick = (artist: string) => { const handleArtistClick = (artist: string) => {
setSelectedArtist(artist); setSelectedArtist(artist);

View File

@ -3,6 +3,7 @@ import { InfiniteScrollList, SongItem } from '../../components/common';
import { useFavorites } from '../../hooks'; import { useFavorites } from '../../hooks';
import { useAppSelector } from '../../redux'; import { useAppSelector } from '../../redux';
import { selectFavorites } from '../../redux'; import { selectFavorites } from '../../redux';
import { debugLog } from '../../utils/logger';
import type { Song } from '../../types'; import type { Song } from '../../types';
const Favorites: React.FC = () => { const Favorites: React.FC = () => {
@ -18,8 +19,8 @@ const Favorites: React.FC = () => {
const favoritesCount = Object.keys(favorites).length; const favoritesCount = Object.keys(favorites).length;
// Debug logging // Debug logging
console.log('Favorites component - favorites count:', favoritesCount); debugLog('Favorites component - favorites count:', favoritesCount);
console.log('Favorites component - favorites items:', favoritesItems); debugLog('Favorites component - favorites items:', favoritesItems);
return ( return (
<> <>

View File

@ -5,6 +5,7 @@ import { InfiniteScrollList, SongItem } from '../../components/common';
import { useHistory } from '../../hooks'; import { useHistory } from '../../hooks';
import { useAppSelector } from '../../redux'; import { useAppSelector } from '../../redux';
import { selectHistory } from '../../redux'; import { selectHistory } from '../../redux';
import { debugLog } from '../../utils/logger';
import { formatDate } from '../../utils/dataProcessing'; import { formatDate } from '../../utils/dataProcessing';
import type { Song } from '../../types'; import type { Song } from '../../types';
@ -21,8 +22,8 @@ const History: React.FC = () => {
const historyCount = Object.keys(history).length; const historyCount = Object.keys(history).length;
// Debug logging // Debug logging
console.log('History component - history count:', historyCount); debugLog('History component - history count:', historyCount);
console.log('History component - history items:', historyItems); debugLog('History component - history items:', historyItems);
// Render extra content for history items (play date) // Render extra content for history items (play date)
const renderExtraContent = (item: Song) => { const renderExtraContent = (item: Song) => {

View File

@ -3,6 +3,7 @@ import { InfiniteScrollList, SongItem } from '../../components/common';
import { useNewSongs } from '../../hooks'; import { useNewSongs } from '../../hooks';
import { useAppSelector } from '../../redux'; import { useAppSelector } from '../../redux';
import { selectNewSongs } from '../../redux'; import { selectNewSongs } from '../../redux';
import { debugLog } from '../../utils/logger';
import type { Song } from '../../types'; import type { Song } from '../../types';
const NewSongs: React.FC = () => { const NewSongs: React.FC = () => {
@ -18,8 +19,8 @@ const NewSongs: React.FC = () => {
const newSongsCount = Object.keys(newSongs).length; const newSongsCount = Object.keys(newSongs).length;
// Debug logging // Debug logging
console.log('NewSongs component - new songs count:', newSongsCount); debugLog('NewSongs component - new songs count:', newSongsCount);
console.log('NewSongs component - new songs items:', newSongsItems); debugLog('NewSongs component - new songs items:', newSongsItems);
return ( return (
<> <>

View File

@ -7,6 +7,7 @@ import { useAppSelector } from '../../redux';
import { selectQueue, selectPlayerState, selectIsAdmin, selectControllerName } from '../../redux'; import { selectQueue, selectPlayerState, selectIsAdmin, selectControllerName } from '../../redux';
import { PlayerState } from '../../types'; import { PlayerState } from '../../types';
import { queueService } from '../../firebase/services'; import { queueService } from '../../firebase/services';
import { debugLog } from '../../utils/logger';
import type { QueueItem } from '../../types'; import type { QueueItem } from '../../types';
type QueueMode = 'delete' | 'reorder'; type QueueMode = 'delete' | 'reorder';
@ -29,18 +30,18 @@ const Queue: React.FC = () => {
const queueCount = Object.keys(queue).length; const queueCount = Object.keys(queue).length;
// Debug logging // Debug logging
console.log('Queue component - queue count:', queueCount); debugLog('Queue component - queue count:', queueCount);
console.log('Queue component - queue items:', queueItems); debugLog('Queue component - queue items:', queueItems);
console.log('Queue component - player state:', playerState); debugLog('Queue component - player state:', playerState);
console.log('Queue component - isAdmin:', isAdmin); debugLog('Queue component - isAdmin:', isAdmin);
console.log('Queue component - canReorder:', canReorder); debugLog('Queue component - canReorder:', canReorder);
console.log('Queue component - queueMode:', queueMode); debugLog('Queue component - queueMode:', queueMode);
// Check if items can be deleted (admin can delete any item when not playing) // 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); const canDeleteItems = isAdmin && (playerState?.state === PlayerState.stopped || playerState?.state === PlayerState.paused);
console.log('Queue component - canDeleteItems:', canDeleteItems); debugLog('Queue component - canDeleteItems:', canDeleteItems);
console.log('Queue component - canReorder:', canReorder); debugLog('Queue component - canReorder:', canReorder);
// Update list items when queue changes // Update list items when queue changes
@ -60,7 +61,7 @@ const Queue: React.FC = () => {
// Handle reorder event from IonReorderGroup // Handle reorder event from IonReorderGroup
const doReorder = async (event: CustomEvent) => { const doReorder = async (event: CustomEvent) => {
console.log('Reorder event:', event.detail); debugLog('Reorder event:', event.detail);
const { from, to, complete } = event.detail; const { from, to, complete } = event.detail;
if (listItems && controllerName) { if (listItems && controllerName) {
@ -73,21 +74,21 @@ const Queue: React.FC = () => {
// Create the new queue order (first item + reordered items) // Create the new queue order (first item + reordered items)
const newQueueItems = [queueItems[0], ...copy]; const newQueueItems = [queueItems[0], ...copy];
console.log('New queue order:', newQueueItems); debugLog('New queue order:', newQueueItems);
try { try {
// Update all items with their new order values // Update all items with their new order values
const updatePromises = newQueueItems.map((item, index) => { const updatePromises = newQueueItems.map((item, index) => {
const newOrder = index + 1; const newOrder = index + 1;
if (item.key && item.order !== newOrder) { if (item.key && item.order !== newOrder) {
console.log(`Updating item ${item.key} from order ${item.order} to ${newOrder}`); debugLog(`Updating item ${item.key} from order ${item.order} to ${newOrder}`);
return queueService.updateQueueItem(controllerName, item.key, { order: newOrder }); return queueService.updateQueueItem(controllerName, item.key, { order: newOrder });
} }
return Promise.resolve(); return Promise.resolve();
}); });
await Promise.all(updatePromises); await Promise.all(updatePromises);
console.log('Queue reorder completed successfully'); debugLog('Queue reorder completed successfully');
} catch (error) { } catch (error) {
console.error('Failed to reorder queue:', error); console.error('Failed to reorder queue:', error);
// You might want to show an error toast here // You might want to show an error toast here
@ -97,7 +98,7 @@ const Queue: React.FC = () => {
// Render queue item // Render queue item
const renderQueueItem = (queueItem: QueueItem, index: number) => { const renderQueueItem = (queueItem: QueueItem, index: number) => {
console.log(`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 = isAdmin && queueMode === 'delete'; // Only allow delete in delete mode
return ( return (

View File

@ -4,6 +4,7 @@ import { InfiniteScrollList, SongItem } from '../../components/common';
import { useSearch } from '../../hooks'; import { useSearch } from '../../hooks';
import { useAppSelector } from '../../redux'; import { useAppSelector } from '../../redux';
import { selectIsAdmin, selectSongs } from '../../redux'; import { selectIsAdmin, selectSongs } from '../../redux';
import { debugLog } from '../../utils/logger';
import type { Song } from '../../types'; import type { Song } from '../../types';
const Search: React.FC = () => { const Search: React.FC = () => {
@ -27,15 +28,15 @@ const Search: React.FC = () => {
return () => { return () => {
const endTime = performance.now(); const endTime = performance.now();
const renderTime = endTime - startTime; const renderTime = endTime - startTime;
console.log(`Search component render time: ${renderTime.toFixed(2)}ms`); debugLog(`Search component render time: ${renderTime.toFixed(2)}ms`);
}; };
}); });
// Debug logging // Debug logging
console.log('Search component - songs count:', songsCount); debugLog('Search component - songs count:', songsCount);
console.log('Search component - search results:', searchResults); debugLog('Search component - search results:', searchResults);
console.log('Search component - search term:', searchTerm); debugLog('Search component - search term:', searchTerm);
console.log('Search component - showing:', searchResults.songs.length, 'of', searchResults.count); debugLog('Search component - showing:', searchResults.songs.length, 'of', searchResults.count);
return ( return (
<div className="max-w-4xl mx-auto p-6"> <div className="max-w-4xl mx-auto p-6">

View File

@ -6,6 +6,7 @@ import { selectIsAdmin, selectSettings } from '../../redux';
import { useDisabledSongs } from '../../hooks'; import { useDisabledSongs } from '../../hooks';
import { InfiniteScrollList, ActionButton } from '../../components/common'; import { InfiniteScrollList, ActionButton } from '../../components/common';
import { filterSongs } from '../../utils/dataProcessing'; import { filterSongs } from '../../utils/dataProcessing';
import { setDebugEnabled, isDebugEnabled, debugLog } from '../../utils/logger';
import type { Song } from '../../types'; import type { Song } from '../../types';
interface DisabledSongDisplay { interface DisabledSongDisplay {
@ -44,7 +45,11 @@ const Settings: React.FC = () => {
const handleToggleSetting = async (setting: string, value: boolean) => { const handleToggleSetting = async (setting: string, value: boolean) => {
// This would need to be implemented with the settings service // This would need to be implemented with the settings service
console.log(`Toggle ${setting} to ${value}`); debugLog(`Toggle ${setting} to ${value}`);
};
const handleToggleDebug = (enabled: boolean) => {
setDebugEnabled(enabled);
}; };
const handleRemoveDisabledSong = async (song: DisabledSongDisplay) => { const handleRemoveDisabledSong = async (song: DisabledSongDisplay) => {
@ -89,6 +94,14 @@ const Settings: React.FC = () => {
onIonChange={(e) => handleToggleSetting('userpick', e.detail.checked)} onIonChange={(e) => handleToggleSetting('userpick', e.detail.checked)}
/> />
</IonItem> </IonItem>
<IonItem>
<IonLabel>Debug Logging</IonLabel>
<IonToggle
slot="end"
checked={isDebugEnabled()}
onIonChange={(e) => handleToggleDebug(e.detail.checked)}
/>
</IonItem>
</IonList> </IonList>
</div> </div>

View File

@ -5,6 +5,7 @@ import { InfiniteScrollList, ActionButton } from '../../components/common';
import { useSingers } from '../../hooks'; import { useSingers } from '../../hooks';
import { useAppSelector } from '../../redux'; import { useAppSelector } from '../../redux';
import { selectSingers } from '../../redux'; import { selectSingers } from '../../redux';
import { debugLog } from '../../utils/logger';
import type { Singer } from '../../types'; import type { Singer } from '../../types';
const Singers: React.FC = () => { const Singers: React.FC = () => {
@ -39,8 +40,8 @@ const Singers: React.FC = () => {
const singersCount = Object.keys(singersData).length; const singersCount = Object.keys(singersData).length;
// Debug logging // Debug logging
console.log('Singers component - singers count:', singersCount); debugLog('Singers component - singers count:', singersCount);
console.log('Singers component - singers:', singers); debugLog('Singers component - singers:', singers);
// Render singer item for InfiniteScrollList // Render singer item for InfiniteScrollList
const renderSingerItem = (singer: Singer) => ( const renderSingerItem = (singer: Singer) => (

View File

@ -6,12 +6,13 @@ import { useAppSelector } from '../../redux';
import { selectTopPlayed, selectSongsArray } from '../../redux'; import { selectTopPlayed, selectSongsArray } from '../../redux';
import { InfiniteScrollList, SongItem } from '../../components/common'; import { InfiniteScrollList, SongItem } from '../../components/common';
import { filterSongs } from '../../utils/dataProcessing'; import { filterSongs } from '../../utils/dataProcessing';
import { debugLog } from '../../utils/logger';
import { useSongOperations } from '../../hooks'; import { useSongOperations } from '../../hooks';
import { useToast } from '../../hooks'; import { useToast } from '../../hooks';
import type { TopPlayed, Song } from '../../types'; import type { TopPlayed, Song } from '../../types';
const Top100: React.FC = () => { const Top100: React.FC = () => {
console.log('Top100 component - RENDERING START'); debugLog('Top100 component - RENDERING START');
const { const {
topPlayedItems, topPlayedItems,
@ -27,7 +28,7 @@ const Top100: React.FC = () => {
const { showSuccess, showError } = useToast(); const { showSuccess, showError } = useToast();
const [selectedTopPlayed, setSelectedTopPlayed] = useState<TopPlayed | null>(null); const [selectedTopPlayed, setSelectedTopPlayed] = useState<TopPlayed | null>(null);
console.log('Top100 component - Redux data:', { topPlayedCount, topPlayedItems: topPlayedItems.length }); debugLog('Top100 component - Redux data:', { topPlayedCount, topPlayedItems: topPlayedItems.length });
const handleTopPlayedClick = useCallback((item: TopPlayed) => { const handleTopPlayedClick = useCallback((item: TopPlayed) => {
setSelectedTopPlayed(item); setSelectedTopPlayed(item);
@ -44,7 +45,7 @@ const Top100: React.FC = () => {
// Use the shared search function with title and artist // Use the shared search function with title and artist
const searchTerm = `${selectedTopPlayed.title} ${selectedTopPlayed.artist}`; const searchTerm = `${selectedTopPlayed.title} ${selectedTopPlayed.artist}`;
console.log('Top100 - Search details:', { debugLog('Top100 - Search details:', {
selectedTopPlayed, selectedTopPlayed,
searchTerm, searchTerm,
allSongsCount: allSongs.length allSongsCount: allSongs.length
@ -52,7 +53,7 @@ const Top100: React.FC = () => {
const filteredSongs = filterSongs(allSongs, searchTerm); const filteredSongs = filterSongs(allSongs, searchTerm);
console.log('Top100 - Search results:', { debugLog('Top100 - Search results:', {
filteredSongsCount: filteredSongs.length, filteredSongsCount: filteredSongs.length,
firstFewResults: filteredSongs.slice(0, 3).map(s => `${s.artist} - ${s.title}`) firstFewResults: filteredSongs.slice(0, 3).map(s => `${s.artist} - ${s.title}`)
}); });
@ -83,7 +84,7 @@ const Top100: React.FC = () => {
const displayCount = topPlayedItems.length; const displayCount = topPlayedItems.length;
const displayHasMore = hasMore; const displayHasMore = hasMore;
console.log('Top100 component - Real Firebase data:', { debugLog('Top100 component - Real Firebase data:', {
displayItems: displayItems.length, displayItems: displayItems.length,
displayCount, displayCount,
displayHasMore, displayHasMore,
@ -93,7 +94,7 @@ const Top100: React.FC = () => {
isLoading isLoading
}); });
console.log('Top100 component - About to render JSX'); debugLog('Top100 component - About to render JSX');
return ( return (
<> <>

View File

@ -9,6 +9,7 @@ import {
update update
} from 'firebase/database'; } from 'firebase/database';
import { database } from './config'; import { database } from './config';
import { debugLog } from '../utils/logger';
import type { Song, QueueItem, Controller, Singer, DisabledSong } from '../types'; import type { Song, QueueItem, Controller, Singer, DisabledSong } from '../types';
// Basic CRUD operations for controllers // Basic CRUD operations for controllers
@ -336,7 +337,7 @@ export const disabledSongsService = {
// Add a song to the disabled list // Add a song to the disabled list
addDisabledSong: async (controllerName: string, song: Song) => { addDisabledSong: async (controllerName: string, song: Song) => {
console.log('disabledSongsService.addDisabledSong called with:', { controllerName, song }); debugLog('disabledSongsService.addDisabledSong called with:', { controllerName, song });
if (!controllerName) { if (!controllerName) {
throw new Error('Controller name is required'); throw new Error('Controller name is required');
@ -351,7 +352,7 @@ export const disabledSongsService = {
} }
const songKey = disabledSongsService.generateSongKey(song.path); const songKey = disabledSongsService.generateSongKey(song.path);
console.log('Generated song key:', songKey); debugLog('Generated song key:', songKey);
const disabledSongRef = ref(database, `controllers/${controllerName}/disabledSongs/${songKey}`); const disabledSongRef = ref(database, `controllers/${controllerName}/disabledSongs/${songKey}`);
const disabledSong = { const disabledSong = {
@ -362,9 +363,9 @@ export const disabledSongsService = {
disabledAt: new Date().toISOString(), disabledAt: new Date().toISOString(),
}; };
console.log('Saving disabled song:', disabledSong); debugLog('Saving disabled song:', disabledSong);
await set(disabledSongRef, disabledSong); await set(disabledSongRef, disabledSong);
console.log('Disabled song saved successfully'); debugLog('Disabled song saved successfully');
}, },
// Remove a song from the disabled list // Remove a song from the disabled list

View File

@ -1,5 +1,6 @@
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { useAppSelector, selectArtistsArray, selectSongsArray } from '../redux'; import { useAppSelector, selectArtistsArray, selectSongsArray } from '../redux';
import { debugLog } from '../utils/logger';
import { useSongOperations } from './useSongOperations'; import { useSongOperations } from './useSongOperations';
import { useToast } from './useToast'; import { useToast } from './useToast';
import type { Song } from '../types'; import type { Song } from '../types';
@ -55,17 +56,17 @@ export const useArtists = () => {
}, [artists.length, filteredArtists.length]); }, [artists.length, filteredArtists.length]);
const loadMore = useCallback(() => { const loadMore = useCallback(() => {
console.log('useArtists - loadMore called:', { debugLog('useArtists - loadMore called:', {
hasMore, hasMore,
currentPage, currentPage,
filteredArtistsLength: filteredArtists.length, filteredArtistsLength: filteredArtists.length,
artistsLength: artists.length artistsLength: artists.length
}); });
if (hasMore) { if (hasMore) {
console.log('useArtists - Incrementing page from', currentPage, 'to', currentPage + 1); debugLog('useArtists - Incrementing page from', currentPage, 'to', currentPage + 1);
setCurrentPage(prev => prev + 1); setCurrentPage(prev => prev + 1);
} else { } else {
console.log('useArtists - Not loading more because hasMore is false'); debugLog('useArtists - Not loading more because hasMore is false');
} }
}, [hasMore, currentPage, filteredArtists.length, artists.length]); }, [hasMore, currentPage, filteredArtists.length, artists.length]);

View File

@ -2,6 +2,7 @@ import { useState, useEffect, useCallback } from 'react';
import { disabledSongsService } from '../firebase/services'; import { disabledSongsService } from '../firebase/services';
import { useAppSelector } from '../redux'; import { useAppSelector } from '../redux';
import { selectControllerName } from '../redux'; import { selectControllerName } from '../redux';
import { debugLog } from '../utils/logger';
import { useToast } from './useToast'; import { useToast } from './useToast';
import type { Song, DisabledSong } from '../types'; import type { Song, DisabledSong } from '../types';
@ -66,7 +67,7 @@ export const useDisabledSongs = () => {
} }
try { try {
console.log('Adding disabled song:', { controllerName, song }); debugLog('Adding disabled song:', { controllerName, song });
await disabledSongsService.addDisabledSong(controllerName, song); await disabledSongsService.addDisabledSong(controllerName, song);
showSuccess('Song marked as disabled'); showSuccess('Song marked as disabled');
} catch (error) { } catch (error) {

View File

@ -1,5 +1,6 @@
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 { useSongOperations } from './useSongOperations'; import { useSongOperations } from './useSongOperations';
import { useToast } from './useToast'; import { useToast } from './useToast';
import { useDisabledSongs } from './useDisabledSongs'; import { useDisabledSongs } from './useDisabledSongs';
@ -28,7 +29,7 @@ export const useFavorites = () => {
}, [favoritesItems.length, allFavoritesItems.length, filterDisabledSongs]); }, [favoritesItems.length, allFavoritesItems.length, filterDisabledSongs]);
const loadMore = useCallback(() => { const loadMore = useCallback(() => {
console.log('useFavorites - loadMore called:', { hasMore, currentPage, allFavoritesItemsLength: allFavoritesItems.length }); debugLog('useFavorites - loadMore called:', { hasMore, currentPage, allFavoritesItemsLength: allFavoritesItems.length });
if (hasMore) { if (hasMore) {
setCurrentPage(prev => prev + 1); setCurrentPage(prev => prev + 1);
} }

View File

@ -1,5 +1,6 @@
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 { useSongOperations } from './useSongOperations'; import { useSongOperations } from './useSongOperations';
import { useToast } from './useToast'; import { useToast } from './useToast';
import { useDisabledSongs } from './useDisabledSongs'; import { useDisabledSongs } from './useDisabledSongs';
@ -28,7 +29,7 @@ export const useHistory = () => {
}, [historyItems.length, allHistoryItems.length, filterDisabledSongs]); }, [historyItems.length, allHistoryItems.length, filterDisabledSongs]);
const loadMore = useCallback(() => { const loadMore = useCallback(() => {
console.log('useHistory - loadMore called:', { hasMore, currentPage, allHistoryItemsLength: allHistoryItems.length }); debugLog('useHistory - loadMore called:', { hasMore, currentPage, allHistoryItemsLength: allHistoryItems.length });
if (hasMore) { if (hasMore) {
setCurrentPage(prev => prev + 1); setCurrentPage(prev => prev + 1);
} }

View File

@ -1,5 +1,6 @@
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { useAppSelector, selectNewSongsArray } from '../redux'; import { useAppSelector, selectNewSongsArray } from '../redux';
import { debugLog } from '../utils/logger';
import { useSongOperations } from './useSongOperations'; import { useSongOperations } from './useSongOperations';
import { useToast } from './useToast'; import { useToast } from './useToast';
import { useDisabledSongs } from './useDisabledSongs'; import { useDisabledSongs } from './useDisabledSongs';
@ -28,7 +29,7 @@ export const useNewSongs = () => {
}, [newSongsItems.length, allNewSongsItems.length, filterDisabledSongs]); }, [newSongsItems.length, allNewSongsItems.length, filterDisabledSongs]);
const loadMore = useCallback(() => { const loadMore = useCallback(() => {
console.log('useNewSongs - loadMore called:', { hasMore, currentPage, allNewSongsItemsLength: allNewSongsItems.length }); debugLog('useNewSongs - loadMore called:', { hasMore, currentPage, allNewSongsItemsLength: allNewSongsItems.length });
if (hasMore) { if (hasMore) {
setCurrentPage(prev => prev + 1); setCurrentPage(prev => prev + 1);
} }

View File

@ -4,6 +4,7 @@ import { useSongOperations } from './useSongOperations';
import { useToast } from './useToast'; import { useToast } from './useToast';
import { queueService } from '../firebase/services'; import { queueService } from '../firebase/services';
import { selectControllerName } from '../redux'; import { selectControllerName } from '../redux';
import { debugLog } from '../utils/logger';
import type { QueueItem } from '../types'; import type { QueueItem } from '../types';
export const useQueue = () => { export const useQueue = () => {
@ -25,7 +26,7 @@ export const useQueue = () => {
}); });
if (needsFix) { if (needsFix) {
console.log('Fixing queue order...'); debugLog('Fixing queue order...');
try { try {
// Update all items with sequential order // Update all items with sequential order
const updatePromises = queueItems.map((item, index) => { const updatePromises = queueItems.map((item, index) => {
@ -37,7 +38,7 @@ export const useQueue = () => {
}); });
await Promise.all(updatePromises); await Promise.all(updatePromises);
console.log('Queue order fixed successfully'); debugLog('Queue order fixed successfully');
} catch (error) { } catch (error) {
console.error('Failed to fix queue order:', error); console.error('Failed to fix queue order:', error);
} }
@ -83,12 +84,12 @@ export const useQueue = () => {
}, [toggleFavorite, showSuccess, showError]); }, [toggleFavorite, showSuccess, showError]);
const handleMoveUp = useCallback(async (queueItem: QueueItem) => { const handleMoveUp = useCallback(async (queueItem: QueueItem) => {
console.log('handleMoveUp called with:', queueItem); debugLog('handleMoveUp called with:', queueItem);
console.log('Current queueItems:', queueItems); debugLog('Current queueItems:', queueItems);
console.log('Controller name:', controllerName); debugLog('Controller name:', controllerName);
if (!controllerName || !queueItem.key || queueItem.order <= 1) { if (!controllerName || !queueItem.key || queueItem.order <= 1) {
console.log('Early return - conditions not met:', { debugLog('Early return - conditions not met:', {
controllerName: !!controllerName, controllerName: !!controllerName,
queueItemKey: !!queueItem.key, queueItemKey: !!queueItem.key,
order: queueItem.order order: queueItem.order
@ -99,15 +100,15 @@ export const useQueue = () => {
try { try {
// Find the item above this one // Find the item above this one
const itemAbove = queueItems.find(item => item.order === queueItem.order - 1); const itemAbove = queueItems.find(item => item.order === queueItem.order - 1);
console.log('Item above:', itemAbove); debugLog('Item above:', itemAbove);
if (!itemAbove || !itemAbove.key) { if (!itemAbove || !itemAbove.key) {
console.log('No item above found'); debugLog('No item above found');
showError('Cannot move item up'); showError('Cannot move item up');
return; return;
} }
console.log('Swapping orders:', { debugLog('Swapping orders:', {
currentItem: { key: queueItem.key, order: queueItem.order }, currentItem: { key: queueItem.key, order: queueItem.order },
itemAbove: { key: itemAbove.key, order: itemAbove.order } itemAbove: { key: itemAbove.key, order: itemAbove.order }
}); });
@ -118,7 +119,7 @@ export const useQueue = () => {
queueService.updateQueueItem(controllerName, itemAbove.key, { order: queueItem.order }) queueService.updateQueueItem(controllerName, itemAbove.key, { order: queueItem.order })
]); ]);
console.log('Move up completed successfully'); debugLog('Move up completed successfully');
showSuccess('Song moved up in queue'); showSuccess('Song moved up in queue');
} catch (error) { } catch (error) {
console.error('Failed to move song up:', error); console.error('Failed to move song up:', error);
@ -127,12 +128,12 @@ export const useQueue = () => {
}, [controllerName, queueItems, showSuccess, showError]); }, [controllerName, queueItems, showSuccess, showError]);
const handleMoveDown = useCallback(async (queueItem: QueueItem) => { const handleMoveDown = useCallback(async (queueItem: QueueItem) => {
console.log('handleMoveDown called with:', queueItem); debugLog('handleMoveDown called with:', queueItem);
console.log('Current queueItems:', queueItems); debugLog('Current queueItems:', queueItems);
console.log('Controller name:', controllerName); debugLog('Controller name:', controllerName);
if (!controllerName || !queueItem.key || queueItem.order >= queueItems.length) { if (!controllerName || !queueItem.key || queueItem.order >= queueItems.length) {
console.log('Early return - conditions not met:', { debugLog('Early return - conditions not met:', {
controllerName: !!controllerName, controllerName: !!controllerName,
queueItemKey: !!queueItem.key, queueItemKey: !!queueItem.key,
order: queueItem.order, order: queueItem.order,
@ -144,15 +145,15 @@ export const useQueue = () => {
try { try {
// Find the item below this one // Find the item below this one
const itemBelow = queueItems.find(item => item.order === queueItem.order + 1); const itemBelow = queueItems.find(item => item.order === queueItem.order + 1);
console.log('Item below:', itemBelow); debugLog('Item below:', itemBelow);
if (!itemBelow || !itemBelow.key) { if (!itemBelow || !itemBelow.key) {
console.log('No item below found'); debugLog('No item below found');
showError('Cannot move item down'); showError('Cannot move item down');
return; return;
} }
console.log('Swapping orders:', { debugLog('Swapping orders:', {
currentItem: { key: queueItem.key, order: queueItem.order }, currentItem: { key: queueItem.key, order: queueItem.order },
itemBelow: { key: itemBelow.key, order: itemBelow.order } itemBelow: { key: itemBelow.key, order: itemBelow.order }
}); });
@ -163,7 +164,7 @@ export const useQueue = () => {
queueService.updateQueueItem(controllerName, itemBelow.key, { order: queueItem.order }) queueService.updateQueueItem(controllerName, itemBelow.key, { order: queueItem.order })
]); ]);
console.log('Move down completed successfully'); debugLog('Move down completed successfully');
showSuccess('Song moved down in queue'); showSuccess('Song moved down in queue');
} catch (error) { } catch (error) {
console.error('Failed to move song down:', error); console.error('Failed to move song down:', error);
@ -172,12 +173,12 @@ export const useQueue = () => {
}, [controllerName, queueItems, showSuccess, showError]); }, [controllerName, queueItems, showSuccess, showError]);
const handleReorder = useCallback(async (oldIndex: number, newIndex: number) => { const handleReorder = useCallback(async (oldIndex: number, newIndex: number) => {
console.log('handleReorder called with:', { oldIndex, newIndex }); debugLog('handleReorder called with:', { oldIndex, newIndex });
console.log('Current queueItems:', queueItems); debugLog('Current queueItems:', queueItems);
console.log('Controller name:', controllerName); debugLog('Controller name:', controllerName);
if (!controllerName || oldIndex === newIndex) { if (!controllerName || oldIndex === newIndex) {
console.log('Early return - conditions not met:', { debugLog('Early return - conditions not met:', {
controllerName: !!controllerName, controllerName: !!controllerName,
oldIndex, oldIndex,
newIndex newIndex
@ -188,12 +189,12 @@ export const useQueue = () => {
try { try {
const itemToMove = queueItems[oldIndex]; const itemToMove = queueItems[oldIndex];
if (!itemToMove || !itemToMove.key) { if (!itemToMove || !itemToMove.key) {
console.log('No item to move found'); debugLog('No item to move found');
showError('Cannot reorder item'); showError('Cannot reorder item');
return; return;
} }
console.log('Moving item:', { debugLog('Moving item:', {
item: { key: itemToMove.key, order: itemToMove.order }, item: { key: itemToMove.key, order: itemToMove.order },
fromIndex: oldIndex, fromIndex: oldIndex,
toIndex: newIndex toIndex: newIndex
@ -233,7 +234,7 @@ export const useQueue = () => {
); );
await Promise.all(updatePromises); await Promise.all(updatePromises);
console.log('Reorder completed successfully'); debugLog('Reorder completed successfully');
showSuccess('Queue reordered successfully'); showSuccess('Queue reordered successfully');
} catch (error) { } catch (error) {
console.error('Failed to reorder queue:', error); console.error('Failed to reorder queue:', error);

View File

@ -1,5 +1,6 @@
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { useAppSelector, selectSongListArray, selectSongsArray } from '../redux'; import { useAppSelector, selectSongListArray, selectSongsArray } from '../redux';
import { debugLog } from '../utils/logger';
import { useSongOperations } from './useSongOperations'; import { useSongOperations } from './useSongOperations';
import { useToast } from './useToast'; import { useToast } from './useToast';
import type { SongListSong, Song } from '../types'; import type { SongListSong, Song } from '../types';
@ -23,7 +24,7 @@ export const useSongLists = () => {
const hasMore = useMemo(() => { const hasMore = useMemo(() => {
// Show "hasMore" if there are more items than currently loaded // Show "hasMore" if there are more items than currently loaded
const hasMoreItems = songLists.length < allSongLists.length; const hasMoreItems = songLists.length < allSongLists.length;
console.log('useSongLists - hasMore calculation:', { debugLog('useSongLists - hasMore calculation:', {
songListsLength: songLists.length, songListsLength: songLists.length,
allSongListsLength: allSongLists.length, allSongListsLength: allSongLists.length,
hasMore: hasMoreItems, hasMore: hasMoreItems,
@ -36,7 +37,7 @@ export const useSongLists = () => {
const endIndex = currentPage * ITEMS_PER_PAGE; const endIndex = currentPage * ITEMS_PER_PAGE;
const hasMoreItems = endIndex < allSongLists.length; const hasMoreItems = endIndex < allSongLists.length;
console.log('useSongLists - loadMore called:', { debugLog('useSongLists - loadMore called:', {
hasMoreItems, hasMoreItems,
currentPage, currentPage,
allSongListsLength: allSongLists.length, allSongListsLength: allSongLists.length,
@ -44,10 +45,10 @@ export const useSongLists = () => {
}); });
if (hasMoreItems) { if (hasMoreItems) {
console.log('useSongLists - Incrementing page from', currentPage, 'to', currentPage + 1); debugLog('useSongLists - Incrementing page from', currentPage, 'to', currentPage + 1);
setCurrentPage(prev => prev + 1); setCurrentPage(prev => prev + 1);
} else { } else {
console.log('useSongLists - Not loading more because hasMore is false'); debugLog('useSongLists - Not loading more because hasMore is false');
} }
}, [currentPage, allSongLists.length]); }, [currentPage, allSongLists.length]);

View File

@ -1,5 +1,6 @@
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useMemo, useState } from 'react';
import { useAppSelector, selectTopPlayedArray } from '../redux'; import { useAppSelector, selectTopPlayedArray } from '../redux';
import { debugLog } from '../utils/logger';
import { useSongOperations } from './useSongOperations'; import { useSongOperations } from './useSongOperations';
import { useToast } from './useToast'; import { useToast } from './useToast';
import type { TopPlayed } from '../types'; import type { TopPlayed } from '../types';
@ -18,7 +19,7 @@ export const useTopPlayed = () => {
const topPlayedItems = useMemo(() => { const topPlayedItems = useMemo(() => {
const endIndex = currentPage * ITEMS_PER_PAGE; const endIndex = currentPage * ITEMS_PER_PAGE;
const result = allTopPlayedItems.slice(0, endIndex); const result = allTopPlayedItems.slice(0, endIndex);
console.log('useTopPlayed - pagination:', { debugLog('useTopPlayed - pagination:', {
currentPage, currentPage,
ITEMS_PER_PAGE, ITEMS_PER_PAGE,
endIndex, endIndex,
@ -31,7 +32,7 @@ export const useTopPlayed = () => {
const hasMore = useMemo(() => { const hasMore = useMemo(() => {
// Show "hasMore" if there are more items than currently loaded // Show "hasMore" if there are more items than currently loaded
const result = topPlayedItems.length < allTopPlayedItems.length; const result = topPlayedItems.length < allTopPlayedItems.length;
console.log('useTopPlayed - hasMore calculation:', { debugLog('useTopPlayed - hasMore calculation:', {
topPlayedItemsLength: topPlayedItems.length, topPlayedItemsLength: topPlayedItems.length,
allTopPlayedItemsLength: allTopPlayedItems.length, allTopPlayedItemsLength: allTopPlayedItems.length,
result result
@ -40,7 +41,7 @@ export const useTopPlayed = () => {
}, [topPlayedItems.length, allTopPlayedItems.length]); }, [topPlayedItems.length, allTopPlayedItems.length]);
const loadMore = useCallback(() => { const loadMore = useCallback(() => {
console.log('useTopPlayed - loadMore called:', { hasMore, currentPage, allTopPlayedItemsLength: allTopPlayedItems.length }); debugLog('useTopPlayed - loadMore called:', { hasMore, currentPage, allTopPlayedItemsLength: allTopPlayedItems.length });
if (hasMore && !isLoading) { if (hasMore && !isLoading) {
setIsLoading(true); setIsLoading(true);
// Simulate a small delay to show loading state // Simulate a small delay to show loading state

View File

@ -1,3 +1,4 @@
import { debugLog } from './logger';
import type { Song, QueueItem, TopPlayed } from '../types'; import type { Song, QueueItem, TopPlayed } from '../types';
// Convert Firebase object to array with keys // Convert Firebase object to array with keys
@ -83,7 +84,7 @@ export const sortSongsByArtistAndTitle = (songs: Song[]): Song[] => {
// Debug logging for first few songs to verify sorting // Debug logging for first few songs to verify sorting
if (sortedSongs.length > 0) { if (sortedSongs.length > 0) {
console.log('Songs sorted by artist and title. First 5 songs:', debugLog('Songs sorted by artist and title. First 5 songs:',
sortedSongs.slice(0, 5).map(s => `${s.artist} - ${s.title}`) sortedSongs.slice(0, 5).map(s => `${s.artist} - ${s.title}`)
); );
} }

36
src/utils/logger.ts Normal file
View File

@ -0,0 +1,36 @@
// Global debug setting - can be controlled from settings
let debugEnabled = false;
// Setter function to control debug logging
export const setDebugEnabled = (enabled: boolean) => {
debugEnabled = enabled;
};
// Getter function to check if debug is enabled
export const isDebugEnabled = () => debugEnabled;
// Main logging function that takes the same arguments as console.log
export const debugLog = (...args: unknown[]) => {
if (debugEnabled) {
console.log(...args);
}
};
// Convenience functions for different log levels
export const debugInfo = (...args: unknown[]) => {
if (debugEnabled) {
console.info(...args);
}
};
export const debugWarn = (...args: unknown[]) => {
if (debugEnabled) {
console.warn(...args);
}
};
export const debugError = (...args: unknown[]) => {
if (debugEnabled) {
console.error(...args);
}
};