singsalot/src/features/Artists/Artists.tsx

115 lines
3.7 KiB
TypeScript

import React, { useState } from 'react';
import { IonSearchbar, IonModal, IonHeader, IonToolbar, IonTitle, IonButton, IonIcon, IonContent } from '@ionic/react';
import { close, list } from 'ionicons/icons';
import { InfiniteScrollList, SongItem, ListItem } from '../../components/common';
import { useArtists } from '../../hooks';
import { useAppSelector } from '../../redux';
import { selectSongs } from '../../redux';
import { debugLog } from '../../utils/logger';
const Artists: React.FC = () => {
const {
artists,
searchTerm,
hasMore,
loadMore,
handleSearchChange,
getSongsByArtist,
getSongCountByArtist,
handleAddToQueue,
handleToggleFavorite,
} = useArtists();
const songs = useAppSelector(selectSongs);
const songsCount = Object.keys(songs).length;
const [selectedArtist, setSelectedArtist] = useState<string | null>(null);
// Debug logging
debugLog('Artists component - artists count:', artists.length);
debugLog('Artists component - selected artist:', selectedArtist);
debugLog('Artists component - songs count:', songsCount);
debugLog('Artists component - search term:', searchTerm);
const handleArtistClick = (artist: string) => {
setSelectedArtist(artist);
};
const handleCloseArtistSongs = () => {
setSelectedArtist(null);
};
const selectedArtistSongs = selectedArtist ? getSongsByArtist(selectedArtist) : [];
// Render artist item for InfiniteScrollList
const renderArtistItem = (artist: string) => (
<ListItem
primaryText={artist}
secondaryText={`${getSongCountByArtist(artist)} song${getSongCountByArtist(artist) !== 1 ? 's' : ''}`}
icon={list}
onClick={() => handleArtistClick(artist)}
/>
);
return (
<>
<div className="max-w-4xl mx-auto p-6">
<div className="mb-6">
{/* Search Input */}
<IonSearchbar
placeholder="Search artists..."
value={searchTerm}
onIonInput={(e) => handleSearchChange(e.detail.value || '')}
debounce={300}
showClearButton="focus"
/>
</div>
{/* Artists List */}
<InfiniteScrollList<string>
items={artists}
isLoading={songsCount === 0}
hasMore={hasMore}
onLoadMore={loadMore}
renderItem={renderArtistItem}
emptyTitle={searchTerm ? "No artists found" : "No artists available"}
emptyMessage={searchTerm ? "Try adjusting your search terms" : "Artists will appear here once songs are loaded"}
loadingTitle="Loading artists..."
loadingMessage="Please wait while songs are being loaded from the database"
/>
{/* Artist Songs Modal */}
<IonModal
isOpen={!!selectedArtist}
onDidDismiss={handleCloseArtistSongs}
breakpoints={[0, 0.5, 0.8]}
initialBreakpoint={0.8}
>
<IonHeader>
<IonToolbar>
<IonTitle>Songs by {selectedArtist}</IonTitle>
<IonButton slot="end" fill="clear" onClick={handleCloseArtistSongs}>
<IonIcon icon={close} />
</IonButton>
</IonToolbar>
</IonHeader>
<IonContent>
<div className="p-4">
{selectedArtistSongs.map((song) => (
<SongItem
key={song.key}
song={song}
context="search"
onAddToQueue={() => handleAddToQueue(song)}
onToggleFavorite={() => handleToggleFavorite(song)}
/>
))}
</div>
</IonContent>
</IonModal>
</div>
</>
);
};
export default Artists;