Compare commits

...

4 Commits

5 changed files with 35 additions and 8 deletions

View File

@ -15,7 +15,7 @@ A real-time karaoke application designed for in-home party use with multi-user s
- **Artist Browsing** - Browse songs by artist with modal views - **Artist Browsing** - Browse songs by artist with modal views
- **Song Lists** - Predefined song collections with availability matching - **Song Lists** - Predefined song collections with availability matching
- **Top Played** - Popular songs based on play history - **Top Played** - Popular songs based on play history
- **New Songs** - Recently added songs to the catalog (see PRD for implementation details) - **New Songs** - Recently added songs to the catalog (see PRD for implementation details) (see PRD for implementation details) (see PRD for implementation details)
### **Admin Features** ### **Admin Features**
- **Queue Control** - Reorder and delete queue items - **Queue Control** - Reorder and delete queue items

View File

@ -1,4 +1,5 @@
Invoke-WebRequest -Uri "https://us-central1-firebase-herse.cloudfunctions.net/recalculateTopPlayed" ` Invoke-WebRequest -Uri "https://us-central1-firebase-herse.cloudfunctions.net/recalculateTopPlayed" ` -Method POST ` -Headers @{"Content-Type"="application/json"} ` -Body '{"data": {"controllerName": "bsully5150"}}'
>> -Method POST `
>> -Headers @{"Content-Type"="application/json"} ` Invoke-WebRequest -Uri "https://us-central1-firebase-herse.cloudfunctions.net/precompileSongListMatches" -Method POST -Headers @{"Content-Type"="application/json"} -Body '{"data": {"controllerName": "mbrucedogs"}}'
>> -Body '{"data": {"controllerName": "bsully5150"}}'
Invoke-WebRequest -Uri "https://us-central1-firebase-herse.cloudfunctions.net/processAllSongListsFullDatasetCallable" -Method POST -Headers @{"Content-Type"="application/json"} -Body '{"data": {"controllerName": "mbrucedogs"}}'

View File

@ -6,6 +6,7 @@ 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';
import { singerService } from '../../firebase/services';
import type { Authentication } from '../../types'; import type { Authentication } from '../../types';
interface LoginPromptProps { interface LoginPromptProps {
@ -46,6 +47,21 @@ const LoginPrompt: React.FC<LoginPromptProps> = ({ isAdmin, onComplete }) => {
}; };
debugLog('Dispatching auth:', auth); debugLog('Dispatching auth:', auth);
dispatch(setAuth(auth)); dispatch(setAuth(auth));
// Automatically add singer to the singers list if they don't exist
try {
await singerService.addSinger(partyId.trim(), singerName.trim());
debugLog('Singer automatically added to singers list');
} catch (error) {
// If singer already exists, that's fine - just log it
if (error instanceof Error && error.message === 'Singer already exists') {
debugLog('Singer already exists in singers list');
} else {
console.error('Error adding singer automatically:', error);
// Don't block login if singer addition fails
}
}
debugLog('Calling onComplete'); debugLog('Calling onComplete');
onComplete(); onComplete();
} catch (error) { } catch (error) {

View File

@ -10,7 +10,7 @@ import type { SongItemProps, QueueItem, Song } from '../../types';
import { SongItemContext } from '../../types'; import { SongItemContext } from '../../types';
import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types'; import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types';
import { Icons } from '../../constants'; import { Icons } from '../../constants';
import { star } from 'ionicons/icons'; import { star, heart } from 'ionicons/icons';
// Utility function to extract filename from path // Utility function to extract filename from path
const extractFilename = (path: string): string => { const extractFilename = (path: string): string => {
@ -31,12 +31,14 @@ export const SongInfoDisplay: React.FC<{
showCount?: boolean; showCount?: boolean;
showFullPath?: boolean; showFullPath?: boolean;
showTopPlayedStar?: boolean; showTopPlayedStar?: boolean;
showFavoriteHeart?: boolean;
}> = React.memo(({ }> = React.memo(({
song, song,
showPath = false, showPath = false,
showCount = false, showCount = false,
showFullPath = false, showFullPath = false,
showTopPlayedStar = false showTopPlayedStar = false,
showFavoriteHeart = false
}) => { }) => {
return ( return (
<IonLabel> <IonLabel>
@ -59,6 +61,13 @@ export const SongInfoDisplay: React.FC<{
style={{ fontSize: '1rem' }} style={{ fontSize: '1rem' }}
/> />
)} )}
{showFavoriteHeart && (
<IonIcon
icon={heart}
color="danger"
style={{ fontSize: '1rem' }}
/>
)}
{song.title} {song.title}
</div> </div>
<div <div
@ -312,6 +321,7 @@ const SongItem: React.FC<SongItemProps> = React.memo(({
showCount={shouldShowCount} showCount={shouldShowCount}
showFullPath={showFullPath} showFullPath={showFullPath}
showTopPlayedStar={isInTopPlayed} showTopPlayedStar={isInTopPlayed}
showFavoriteHeart={isInFavorites}
/> />
{showActions && ( {showActions && (

View File

@ -34,7 +34,7 @@ const Favorites: React.FC = () => {
song={song} song={song}
context={SongItemContext.FAVORITES} context={SongItemContext.FAVORITES}
showInfoButton={true} showInfoButton={true}
showAddButton={false} showAddButton={true}
showDeleteButton={true} showDeleteButton={true}
onDeleteItem={() => handleToggleFavorite(song)} onDeleteItem={() => handleToggleFavorite(song)}
/> />