singsalot/docs/platforms/web/PRD-web.md

35 KiB

Web Platform Implementation Guide

Platform: Web (React + Ionic + TypeScript)
Core Business Logic: See ../../PRD.md for platform-agnostic requirements

This document contains web-specific implementation details for the Karaoke App. All business logic, data models, and core requirements are defined in the main PRD.


Quick Reference

Section Purpose
UI/UX Behavior Web-specific UI patterns and interactions
Refactored Architecture Latest architecture improvements and patterns
Component Architecture React/Ionic component structure
State Management Redux Toolkit implementation
Performance Optimizations Web-specific performance strategies
Development Setup Web project configuration
Design Assets Web-specific visual references
Toolset Choices Web technology rationale

Refactored Architecture

Overview

The web implementation has been completely refactored to improve maintainability, performance, and developer experience. This section documents the latest architecture patterns and implementation details.

Key Architectural Improvements

1. Domain-Specific Redux Slices

Replaced the monolithic controllerSlice with focused, domain-specific slices:

// Before: Monolithic controllerSlice
src/redux/controllerSlice.ts (1000+ lines)

// After: Domain-specific slices
src/redux/songsSlice.ts      // Song catalog management
src/redux/queueSlice.ts      // Queue operations and state
src/redux/favoritesSlice.ts  // Favorites management
src/redux/historySlice.ts    // History tracking

Benefits:

  • Better Performance - Smaller slices mean faster state updates
  • Easier Testing - Isolated business logic for each domain
  • Improved Maintainability - Clear separation of concerns
  • Reduced Bundle Size - Only load necessary slice logic

2. Composable Hooks

Extracted common patterns into reusable, composable hooks:

// Reusable filtering logic
useFilteredSongs(songs, searchTerm, disabledSongs)

// Generic pagination with search
usePaginatedData(data, pageSize, searchTerm)

// Centralized error handling
useErrorHandler(operation, fallbackMessage)

// Performance monitoring
usePerformanceMonitor(componentName, props)

Benefits:

  • Code Reuse - Common patterns shared across features
  • Performance Optimized - Each hook can be optimized independently
  • Type Safety - Full TypeScript support with proper typing
  • Easier Testing - Isolated business logic

3. Optimized Components

Enhanced components with performance optimizations:

// Memoized SongItem with optimized rendering
const SongItem = React.memo<SongItemProps>(({ song, context, ...props }) => {
  const isInQueue = useMemo(() => /* expensive computation */, [queue, song.path]);
  const handleAddToQueue = useCallback(() => /* action */, [handleAddToQueue, song]);
  
  return <IonItem>...</IonItem>;
});

// Generic ListItem for any data type
const ListItem = React.memo<GenericListItemProps>(({ 
  primaryText, secondaryText, onClick, ...props 
}) => {
  return <IonItem>...</IonItem>;
});

// High-performance virtualized list
const VirtualizedList = <T,>({ 
  items, renderItem, itemHeight, ...props 
}: VirtualizedListProps<T>) => {
  // Only renders visible items
  return <div>...</div>;
};

Benefits:

  • React.memo - Prevents unnecessary re-renders
  • Generic Components - Reusable across different data types
  • Virtualized Rendering - Handles large datasets efficiently
  • Performance Monitoring - Built-in tracking capabilities

Implementation Patterns

State Management Pattern

// Domain-specific slice
export const songsSlice = createSlice({
  name: 'songs',
  initialState,
  reducers: { /* domain-specific actions */ },
  extraReducers: (builder) => {
    builder.addCase(fetchSongs.fulfilled, (state, action) => {
      // Handle async operations
    });
  },
});

// Composable hook using the slice
export const useSongs = () => {
  const dispatch = useAppDispatch();
  const songs = useAppSelector(selectSongs);
  
  const fetchSongs = useCallback(async () => {
    try {
      await dispatch(fetchSongsThunk());
    } catch (error) {
      // Error handling
    }
  }, [dispatch]);
  
  return { songs, fetchSongs };
};

Component Pattern

// Feature component using composable hooks
const Search: React.FC = () => {
  const { songs, loading, error } = useSongs();
  const { filteredSongs, searchTerm, setSearchTerm } = useFilteredSongs(songs);
  const { paginatedData, hasMore, loadMore } = usePaginatedData(filteredSongs);
  
  return (
    <div>
      <SearchInput value={searchTerm} onChange={setSearchTerm} />
      <VirtualizedList
        items={paginatedData}
        renderItem={(song) => <SongItem song={song} context="search" />}
        hasMore={hasMore}
        onLoadMore={loadMore}
      />
    </div>
  );
};

Performance Optimizations

Component-Level Optimizations

  • React.memo - Prevents re-renders when props haven't changed
  • useMemo - Memoizes expensive computations
  • useCallback - Memoizes event handlers and functions
  • Virtualized Lists - Only renders visible items for large datasets

State Management Optimizations

  • Domain-Specific Slices - Smaller, focused state management
  • Memoized Selectors - Efficient state access with reselect
  • Lazy Loading - Load components and data only when needed
  • Incremental Updates - Target specific Firebase nodes for efficiency

Data Handling Optimizations

  • Pagination - Load data in chunks to prevent UI blocking
  • Search Debouncing - Reduce unnecessary API calls during typing
  • Filtering Optimization - Efficient algorithms for large datasets
  • Memory Management - Proper cleanup of listeners and subscriptions

Development Guidelines

Adding New Features

  1. Create domain-specific slice if needed
  2. Implement composable hooks for business logic
  3. Build optimized components with React.memo and useCallback
  4. Add TypeScript types for type safety
  5. Implement error handling using useErrorHandler

Performance Best Practices

  • Use React.memo for expensive components
  • Implement useMemo/useCallback for expensive operations
  • Leverage virtualized lists for large datasets
  • Optimize Redux selectors with memoization
  • Monitor performance with usePerformanceMonitor

Code Organization

  • Domain-specific slices in /redux/
  • Composable hooks in /hooks/
  • Generic components in /components/common/
  • Feature components in /features/
  • TypeScript types in /types/

UI/UX Behavior

Web-Specific Requirements:

Responsive Design:

  • Mobile-first approach with touch-friendly interface
  • Progressive Web App (PWA) capabilities for app-like experience
  • Responsive breakpoints for tablet and desktop views
  • Touch gestures for queue reordering and navigation

Ionic React Components:

  • IonApp as root container with proper theming
  • IonRouterOutlet for navigation between pages
  • IonList and IonItem for song and queue displays
  • IonButton with proper touch targets (44px minimum)
  • IonSearchbar for song search with debounced input
  • IonModal for singer selection and settings
  • IonToast for user feedback and notifications

Navigation Patterns:

  • Tab-based navigation for main sections (Queue, Search, History, etc.)
  • Stack navigation for detail views (song info, artist pages)
  • Modal overlays for quick actions (singer selection, settings)
  • Deep linking support for direct page access

Real-time Updates:

  • Live queue updates with visual indicators for changes
  • Playback state synchronization across all connected devices
  • User presence indicators showing who's currently active
  • Optimistic UI updates with rollback on errors

Codebase Organization & File Structure

Refactored Web Project Structure (Latest):

src/
├── components/          # Reusable UI components
│   ├── Auth/           # Authentication components
│   ├── common/         # Shared components (SongItem, ActionButton, etc.)
│   ├── Layout/         # Layout and navigation components
│   └── Navigation/     # Navigation components
├── features/           # Feature-specific components
│   ├── Artists/        # Artist browsing feature
│   ├── Favorites/      # Favorites management
│   ├── History/        # Play history
│   ├── NewSongs/       # New songs feature
│   ├── Queue/          # Queue management
│   ├── Search/         # Song search
│   ├── Settings/       # Settings and admin features
│   ├── Singers/        # Singer management
│   ├── SongLists/      # Song lists feature
│   └── TopPlayed/      # Top played songs
├── firebase/           # Firebase configuration and services
│   ├── config.ts       # Firebase configuration
│   ├── services.ts     # Firebase service layer
│   └── useFirebase.ts  # Firebase hooks
├── hooks/              # Custom React hooks (refactored)
│   ├── useFilteredSongs.ts    # Reusable song filtering logic
│   ├── usePaginatedData.ts    # Generic pagination with search
│   ├── useErrorHandler.ts     # Centralized error handling
│   ├── usePerformanceMonitor.ts # Performance tracking
│   ├── useQueue.ts     # Queue management hooks
│   ├── useSearch.ts    # Search functionality hooks
│   ├── useFavorites.ts # Favorites management hooks
│   └── ...            # Other feature hooks
├── redux/              # State management (domain-specific slices)
│   ├── store.ts        # Redux store configuration
│   ├── songsSlice.ts   # Song catalog management
│   ├── queueSlice.ts   # Queue operations and state
│   ├── favoritesSlice.ts # Favorites management
│   ├── historySlice.ts # History tracking
│   ├── selectors.ts    # Memoized selectors
│   └── hooks.ts        # Redux hooks
├── types/              # TypeScript type definitions
└── utils/              # Utility functions

Refactored Architecture Benefits:

Domain-Specific Redux Slices:

  • Modular Design - Each slice handles a specific domain (songs, queue, favorites, history)
  • Better Performance - Smaller slices mean faster state updates and re-renders
  • Easier Testing - Isolated business logic for each domain
  • Improved Maintainability - Clear separation of concerns

Composable Hooks:

  • Reusable Logic - Common patterns extracted into reusable hooks
  • Performance Optimized - Each hook can be optimized independently
  • Type Safety - Full TypeScript support with proper typing
  • Error Handling - Centralized error management across the app

Optimized Components:

  • React.memo - Prevents unnecessary re-renders for expensive components
  • Generic Components - Reusable across different data types (ListItem, VirtualizedList)
  • Performance Monitoring - Built-in performance tracking
  • Error Boundaries - Graceful error handling and recovery

File Organization Rules:

Folder Purpose Key Files Import Pattern
/components Reusable UI components SongItem.tsx, ActionButton.tsx, ListItem.tsx import { SongItem } from '../components/common'
/features Feature-specific pages Queue.tsx, Search.tsx import { Queue } from '../features/Queue'
/firebase Firebase integration services.ts, config.ts import { queueService } from '../firebase/services'
/hooks Composable business logic useFilteredSongs.ts, usePaginatedData.ts import { useFilteredSongs } from '../hooks'
/redux Domain-specific state songsSlice.ts, queueSlice.ts import { songsSlice } from '../redux'
/types TypeScript definitions index.ts (extends docs/types.ts) import type { Song, QueueItem } from '../types'

Import Patterns:

1. Redux Imports:

// Always import from the main redux index
import { useAppDispatch, useAppSelector } from '../redux';
import { selectQueue, selectSongs } from '../redux';
import { setController, updateQueue } from '../redux';

// ❌ Don't import directly from slice files
// ❌ import { selectQueue } from '../redux/controllerSlice';
// ✅ Always use the main redux index
// ✅ import { selectQueue } from '../redux';

2. Firebase Service Imports:

// Import services from the main services file
import { queueService, searchService } from '../firebase/services';

// ❌ Don't import directly from individual service files
// ❌ import { addToQueue } from '../firebase/queueService';
// ✅ Always use the main services file
// ✅ import { queueService } from '../firebase/services';

3. Type Imports:

// Always use type imports for TypeScript interfaces
import type { Song, QueueItem, Singer } from '../types';

// ❌ Don't import types from individual files
// ❌ import { Song } from '../types/Song';
// ✅ Always use the main types index
// ✅ import type { Song } from '../types';

4. Hook Imports:

// Import hooks from their specific files
import { useQueue } from '../hooks/useQueue';
import { useSearch } from '../hooks/useSearch';
import { useFavorites } from '../hooks/useFavorites';

// ❌ Don't import from a general hooks index
// ❌ import { useQueue } from '../hooks';
// ✅ Import from specific hook files
// ✅ import { useQueue } from '../hooks/useQueue';

5. Component Imports:

// Import components from their specific folders
import { SongItem } from '../components/common/SongItem';
import { ActionButton } from '../components/common/ActionButton';
import { Layout } from '../components/Layout/Layout';

// ❌ Don't import from general component indices
// ❌ import { SongItem } from '../components';
// ✅ Import from specific component files
// ✅ import { SongItem } from '../components/common/SongItem';

Architecture Flow:

UI Components → Custom Hooks → Redux State → Firebase Services → Firebase Database

Separation of Concerns:

  • Components: Only handle UI presentation and user interactions
  • Hooks: Contain business logic and data management
  • Redux: Manage global application state
  • Services: Handle Firebase operations and data persistence
  • Types: Define data structures and interfaces

Component Architecture

React Component Structure:

Page Components:

// src/features/Queue/Queue.tsx
interface QueueProps {
  // Props interface
}

const Queue: React.FC<QueueProps> = () => {
  // Component implementation
}

Common Components:

// src/components/common/SongItem.tsx
interface SongItemProps {
  song: Song;
  onAddToQueue: (song: Song) => void;
  onAddToFavorites: (song: Song) => void;
  showAddButton?: boolean;
  showFavoriteButton?: boolean;
}

Layout Components:

// src/components/Layout/Layout.tsx
interface LayoutProps {
  children: React.ReactNode;
  title?: string;
  showBackButton?: boolean;
}

Ionic Integration:

  • IonPage wrapper for all page components
  • IonHeader with dynamic titles and action buttons
  • IonContent with proper scrolling behavior
  • IonFooter for player controls and queue management
  • IonLoading for async operations and data fetching

State Management

Redux Architecture Pattern:

The web implementation uses Redux Toolkit for predictable state management with excellent TypeScript support.

Store Structure:

// src/redux/store.ts
export const store = configureStore({
  reducer: {
    auth: authSlice,
    player: playerSlice,
    queue: queueSlice,
    controller: controllerSlice,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: ['persist/PERSIST'],
      },
    }),
});

Slice Patterns:

// src/redux/controllerSlice.ts
const controllerSlice = createSlice({
  name: 'controller',
  initialState,
  reducers: {
    setController: (state, action) => {
      state.data = action.payload;
    },
    updateQueue: (state, action) => {
      state.data.player.queue = action.payload;
    },
  },
});

Selectors:

// src/redux/selectors.ts
export const selectQueue = (state: RootState) => state.controller.data?.player?.queue || {};
export const selectQueueLength = createSelector(
  [selectQueue],
  (queue) => Object.keys(queue).length
);

Redux Toolkit Implementation:

Store Structure:

// src/redux/store.ts
export const store = configureStore({
  reducer: {
    auth: authSlice,
    player: playerSlice,
    queue: queueSlice,
    controller: controllerSlice,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: ['persist/PERSIST'],
      },
    }),
});

Slice Patterns:

// src/redux/queueSlice.ts
const queueSlice = createSlice({
  name: 'queue',
  initialState,
  reducers: {
    addToQueue: (state, action) => {
      // Implementation
    },
    removeFromQueue: (state, action) => {
      // Implementation
    },
  },
});

Selectors:

// src/redux/selectors.ts
export const selectQueue = (state: RootState) => state.queue.items;
export const selectQueueLength = createSelector(
  [selectQueue],
  (queue) => queue.length
);

Development Setup

Project Configuration:

Package.json Dependencies:

{
  "dependencies": {
    "@ionic/react": "^7.0.0",
    "@reduxjs/toolkit": "^1.9.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-redux": "^8.0.0",
    "firebase": "^9.0.0"
  },
  "devDependencies": {
    "@types/react": "^18.0.0",
    "@types/react-dom": "^18.0.0",
    "typescript": "^4.9.0",
    "vite": "^4.0.0"
  }
}

Vite Configuration:

// vite.config.ts
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
  build: {
    outDir: 'dist',
    sourcemap: true,
  },
});

TypeScript Configuration:

// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  }
}

Environment Setup:

# .env.local
VITE_FIREBASE_API_KEY=your_api_key
VITE_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=your_project_id
VITE_FIREBASE_STORAGE_BUCKET=your_project.appspot.com
VITE_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
VITE_FIREBASE_APP_ID=your_app_id
VITE_FIREBASE_DATABASE_URL=https://your_project-default-rtdb.firebaseio.com

Design Assets

Web-Specific Mockups:

Located in design/ with 30+ mockups covering all features:

Core Navigation & Layout:

  • 00-web-layout.JPG - Overall web layout structure
  • 01-Login.png - Login screen design
  • 02-menu.jpeg, 02a-menu.jpeg, 02b-menu.png, 02c-menu.jpeg - Navigation menu variations

Queue Management:

  • 02-queue.png - Main queue view
  • 02-queue-delete.png - Queue with delete functionality
  • 02-queue-drag.png - Queue reordering with drag and drop
  • 02-queue-sorting.png - Queue sorting interface

Search & Discovery:

  • 04-search.png - Main search interface
  • 04-search typing .png - Search with typing interaction
  • 04-search-song info.png - Search results with song information

User Management:

  • 05-singers.png - Singer list view
  • 05-singers add.png - Singer management interface

Content Browsing:

  • 06-artists .png - Artist browse interface
  • 06-artists (not admin).png - Non-admin artist view
  • 06-artists search.png - Artist search functionality
  • 06-artists songs.png - Artist songs list

User Features:

  • 07-favorites.png - Favorites management
  • 08-history.png - Play history view
  • 09-songs list.png - Main song lists view
  • 09-song lists - songs.png - Song lists with song details
  • 09- song lists songs expand.png - Song lists with expandable sections

Admin Features:

  • 10-Settings.png - Settings interface
  • 11-top 100.png - Top played songs
  • 12-favorites .png - Favorites view
  • 12-favorite lists.png - Favorite lists management

Menu States:

  • 03-menu.png - General menu layout
  • 03-menu current page and non-admin.png - Navigation with current page indicators
  • 03-menu playing (admin).png - Admin view during playback

Design System:

  • Ionic Design System for consistent UI components
  • Custom CSS variables for theming and branding
  • Responsive grid system for layout consistency
  • Touch-friendly spacing and sizing guidelines

Toolset Choices

Current Web Implementation Toolset:

Core Framework: React 18 + TypeScript

  • Why: Chosen for its component-based architecture, strong ecosystem, and excellent TypeScript support
  • Migration Note: Can be replaced with any other component-based framework (e.g., Vue, Svelte)

State Management: Redux Toolkit

  • Why: Provides predictable state management with excellent TypeScript support and dev tools
  • Migration Note: Can be replaced with Context API, Zustand, or other state management solutions

UI Framework: Ionic React

  • Why: Provides mobile-first UI components with excellent touch support and PWA capabilities
  • Migration Note: Can be replaced with Material-UI, Chakra UI, or custom components

Build Tool: Vite

  • Why: Fast development server and optimized builds with excellent TypeScript support
  • Migration Note: Can be replaced with Webpack, Parcel, or other build tools

Backend: Firebase Realtime Database

  • Why: Real-time synchronization, simple setup, and excellent React integration
  • Migration Note: Can be replaced with any real-time database (Supabase, AWS AppSync, etc.)

Development Tools:

  • TypeScript: Type safety and better developer experience
  • ESLint: Code quality and consistency
  • Prettier: Code formatting
  • React DevTools: Component debugging
  • Redux DevTools: State management debugging

Web-Specific Implementation Details

Authentication & Session Management:

  • Admin Access: Triggered by URL parameter (?admin=true), removed after login
  • Session Persistence: Lost on browser reload (no persistent storage)
  • Admin Mode: Pre-fills singer name as "Admin" for convenience
  • URL Handling: Admin parameter automatically removed from URL after authentication

Search Implementation:

  • Pagination: Uses Ionic InfiniteScrollList component for efficient loading
  • Debouncing: Search input debounced to prevent excessive API calls
  • Real-time Results: Instant search results as user types
  • Context Actions: Add to queue, favorite, and other actions available per song

Queue Management:

  • UI Controls: Reordering and deletion exposed via UI controls only visible to admins
  • Drag & Drop: Uses Ionic drag handles and swipe actions for reordering
  • Visual Feedback: Clear indicators for admin-only actions
  • State Synchronization: Real-time updates across all connected clients

Favorites Implementation:

  • Infinite Scroll: Uses Ionic InfiniteScrollList for pagination
  • Real-time Sync: Shared favorites list synchronized across all clients
  • Duplicate Prevention: Prevents duplicates using song path field
  • User Actions: Anyone can add/remove favorites

New Songs Implementation:

  • Infinite Scroll: Uses Ionic InfiniteScrollList for pagination
  • Real-time Updates: Shows recently added songs from newSongs node
  • Automatic Loading: Progressive loading as user scrolls

Artists Implementation:

  • Modal Views: Uses Ionic modals for artist song lists
  • Infinite Scroll: Uses Ionic InfiniteScrollList for pagination
  • Search Integration: Artist search functionality included
  • Song Counts: Displays song count per artist

Song Lists Implementation:

  • Modal Interface: Uses Ionic modals for viewing list contents
  • Infinite Scroll: Uses Ionic InfiniteScrollList for pagination
  • Expandable Views: Available versions shown with expandable sections
  • Availability Status: Shows which songs are available in catalog

History Implementation:

  • Infinite Scroll: Uses Ionic InfiniteScrollList for pagination
  • Automatic Tracking: Songs automatically added when played
  • Timestamp Display: Shows when each song was last played
  • Append-only: History is append-only, shared across all clients

Top Played Implementation:

  • Infinite Scroll: Uses Ionic InfiniteScrollList for pagination
  • Play Count Display: Shows play count for each song
  • Real-time Updates: Popular songs generated by backend
  • Backend Integration: Based on history data

Singer Management:

  • Admin-only UI: Singer management available only to admins via settings page
  • Unique Names: Singer names must be unique and non-empty
  • Auto-addition: Singers automatically added when they join
  • Last Join Tracking: Tracks when each singer last joined

Playback Control:

  • Admin-only Controls: Player controls only rendered for admins
  • State-based UI: Play/pause/stop buttons shown/hidden based on current state
  • Queue Validation: Play button disabled when queue is empty
  • Real-time Sync: Playback state synchronized across all clients

Error Handling & Sync:

  • Toast Notifications: Uses web-specific toast notifications for user feedback
  • Error Boundaries: React error boundaries for component-level error handling
  • Retry Patterns: Automatic retry for failed Firebase operations
  • Connection Monitoring: Real-time connection status tracking

Disabled Songs:

  • Modal Management: Disabled songs managed via modal dialog
  • Search & Filter: Search and filter capabilities in management interface
  • Hash Storage: Disabled songs stored using hash of song path
  • Admin-only Access: Only admins can disable or enable songs

Settings Implementation:

  • Debug Logging: Web-only feature, toggled via settings page
  • Admin-only Access: Only admins can change player settings
  • Real-time Updates: Settings changes synchronized across all clients
  • UI Controls: Settings interface with toggle switches and controls

Navigation Implementation:

  • Admin-based Navigation: Navigation adapts based on admin status
  • Hidden Pages: Settings page only visible to admins
  • Role-based UI: Different navigation options for different user roles
  • Dynamic Menus: Menu items shown/hidden based on permissions

UI/UX Implementation:

  • Ionic React: Uses Ionic React and Tailwind CSS for UI
  • Component Library: Infinite scroll, swipe actions, modals, and toasts using Ionic components
  • Responsive Design: Mobile-first approach with touch-friendly interface
  • Theme Support: Light/dark mode support with consistent styling

Implementation Notes

Critical Web-Specific Patterns:

Firebase Integration:

// src/firebase/services.ts
export const queueService = {
  addToQueue: async (song: Song, singerId: string) => {
    const newKey = await getNextKey('queue');
    await set(ref(database, `queue/${newKey}`), {
      songId: song.id,
      singerId,
      timestamp: Date.now(),
      key: newKey,
    });
  },
};

Real-time Listeners:

// src/hooks/useQueue.ts
useEffect(() => {
  const queueRef = ref(database, 'queue');
  const unsubscribe = onValue(queueRef, (snapshot) => {
    const data = snapshot.val();
    if (data) {
      const queueItems = Object.values(data) as QueueItem[];
      dispatch(setQueue(queueItems));
    }
  });
  return () => unsubscribe();
}, [dispatch]);

Error Handling:

// src/hooks/useFirebaseSync.ts
const retryOperation = async (operation: () => Promise<void>, maxRetries = 3) => {
  for (let i = 0; i < maxRetries; i++) {
    try {
      await operation();
      return;
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
    }
  }
};

Hook Implementation Patterns:

Custom Hook Structure:

// src/hooks/useQueue.ts
export const useQueue = () => {
  const dispatch = useAppDispatch();
  const queue = useAppSelector(selectQueue);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const addToQueue = useCallback(async (song: Song, singerId: string) => {
    try {
      setLoading(true);
      setError(null);
      await queueService.addToQueue(song, singerId);
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to add to queue');
    } finally {
      setLoading(false);
    }
  }, []);

  return {
    queue,
    loading,
    error,
    addToQueue,
  };
};

Hook Dependencies:

  • Hooks depend on Redux state and services
  • Business logic implemented in hooks, not components
  • Error handling and loading states managed in hooks
  • Memoization used for expensive operations

Hook Usage in Components:

// src/features/Queue/Queue.tsx
const Queue: React.FC = () => {
  const { queue, loading, error, addToQueue } = useQueue();
  const { songs } = useSongs();

  const handleAddToQueue = useCallback((song: Song) => {
    addToQueue(song, currentSingerId);
  }, [addToQueue, currentSingerId]);

  if (loading) return <LoadingSpinner />;
  if (error) return <ErrorMessage message={error} />;

  return (
    <IonList>
      {Object.values(queue).map((item) => (
        <SongItem
          key={item.key}
          song={songs[item.songId]}
          onAddToQueue={handleAddToQueue}
        />
      ))}
    </IonList>
  );
};

Performance Optimizations:

Component-Level Optimizations:

  • React.memo - Prevents unnecessary re-renders for expensive components like SongItem
  • useMemo/useCallback - Memoizes expensive computations and event handlers
  • Virtualized Lists - VirtualizedList component renders only visible items for large datasets
  • Generic Components - ListItem component works with any data type for reusability

State Management Optimizations:

  • Domain-Specific Slices - Smaller, focused Redux slices (songs, queue, favorites, history)
  • Composable Hooks - Reusable logic (useFilteredSongs, usePaginatedData, useErrorHandler)
  • Optimized Selectors - Memoized Redux selectors for efficient state access
  • Lazy Loading - Components and data loaded only when needed

Data Handling Optimizations:

  • Pagination - usePaginatedData hook loads data in chunks to prevent UI blocking
  • Search Debouncing - Reduces unnecessary API calls during typing
  • Filtering Optimization - useFilteredSongs hook provides efficient filtering algorithms
  • Memory Management - Proper cleanup of listeners and subscriptions

Performance Monitoring:

  • Built-in Performance Hooks - usePerformanceMonitor tracks component render times
  • Error Tracking - Centralized error handling with performance impact monitoring
  • Bundle Analysis - Optimized bundle size with code splitting

Specific Optimizations:

  • SongItem Component - Fully memoized with React.memo, useMemo, and useCallback
  • ListItem Component - Generic component supporting multiple data types
  • VirtualizedList Component - High-performance list rendering with windowing
  • ActionButton Component - Reusable buttons with consistent styling and behavior

Refactoring Benefits & Migration Notes:

Architecture Improvements:

  • Modular Redux Slices - Replaced monolithic controllerSlice with domain-specific slices
  • Composable Hooks - Extracted common patterns into reusable hooks
  • Performance Optimizations - Added React.memo, useMemo, useCallback throughout
  • Type Safety - Enhanced TypeScript support with strict typing

Component Enhancements:

  • Generic ListItem - Replaced song-specific component with generic, reusable component
  • VirtualizedList - Added high-performance list rendering for large datasets
  • Performance Monitoring - Built-in performance tracking with usePerformanceMonitor
  • Error Boundaries - Centralized error handling across the application

Development Experience:

  • Better Maintainability - Clear separation of concerns with domain-specific slices
  • Easier Testing - Isolated business logic for each domain
  • Improved Performance - Optimized rendering and state management
  • Enhanced Type Safety - Full TypeScript coverage with proper typing

Critical Implementation Rules:

  • Never import directly from slice files - always use the main redux index
  • Always use type imports for TypeScript interfaces
  • Implement business logic in hooks, not components
  • Use memoization for expensive operations
  • Handle loading and error states in all async operations
  • Use React.memo for performance-critical components
  • Leverage composable hooks for reusable business logic

Migration Guide

To Other Web Frameworks:

Vue.js Migration:

  • Replace React components with Vue components
  • Replace Redux with Pinia or Vuex
  • Replace Ionic React with Ionic Vue
  • Keep all business logic and Firebase integration

Svelte Migration:

  • Replace React components with Svelte components
  • Replace Redux with Svelte stores
  • Replace Ionic React with Ionic Svelte
  • Keep all business logic and Firebase integration

To Mobile Platforms:

React Native Migration:

  • Replace Ionic components with React Native components
  • Replace web-specific APIs with React Native APIs
  • Keep Redux state management
  • Keep all business logic and Firebase integration

Native iOS/Android Migration:

  • Replace React components with native UI components
  • Replace Redux with native state management
  • Keep all business logic and Firebase integration
  • Adapt UI patterns to platform conventions

This document contains web-specific implementation details. For core business logic and platform-agnostic requirements, see the main ../../PRD.md.