import React, { useState, useEffect, useCallback } from 'react'; import { MediaList } from '../components/MediaList'; import { MediaItem } from '../api/jellyfin'; import { Loader } from '../components/Loader'; import { usePageTitle } from '../context/PageTitleContext/PageTitleContext'; import { useParams } from 'react-router-dom'; interface SectionData { title: string; description?: string; items?: MediaItem[]; tracks?: MediaItem[]; albums?: MediaItem[]; } import { usePullToRefresh } from '../hooks/usePullToRefresh'; import { useScrollRestore } from '../hooks/useScrollRestore'; // InlineLoader no longer used here; replaced by PullToRefreshIndicator import { PullToRefreshIndicator } from '../components/PullToRefreshIndicator'; // Removed icon button; the indicator acts as the actionable target export const SectionMore: React.FC = () => { const { setPageTitle } = usePageTitle(); const { section } = useParams<{ section: string }>(); const [sectionData, setSectionData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const fetchSectionData = useCallback(async () => { setLoading(true); setError(null); try { // Special case: if section is "genres", fetch all genres overview if (section === 'genres') { // Determine the correct backend URL based on environment let fetchUrl; if (window.location.hostname === 'music.samcloud.ca') { fetchUrl = `/api/discover/genres?t=${Date.now()}`; } else { fetchUrl = `http://localhost:5140/api/discover/genres?t=${Date.now()}`; } console.log('Fetching all genres overview from:', fetchUrl); const response = await fetch(fetchUrl); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); console.log('All genres overview data:', data); // Transform the genres data to work with existing UI setSectionData({ title: data.title || 'All Genres', description: data.description || 'Explore music across all available genres', items: data.genres?.flatMap((genre: any) => genre.tracks) || [] }); return; } // Determine the correct backend URL based on environment let fetchUrl; let apiPath; // Handle genre sections (convert genre-Pop to genre/Pop) if (section?.startsWith('genre-')) { const genreName = section.replace('genre-', ''); apiPath = `genre/${genreName}`; } else { apiPath = section; } // Check if we're on the live site if (window.location.hostname === 'music.samcloud.ca') { // Use relative URL for live site (will use the same domain with reverse proxy) fetchUrl = `/api/discover/${apiPath}?limit=100&t=${Date.now()}`; } else { // Use localhost for development fetchUrl = `http://localhost:5140/api/discover/${apiPath}?limit=100&t=${Date.now()}`; } console.log('Fetching section data from:', fetchUrl); const response = await fetch(fetchUrl); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data: SectionData = await response.json(); console.log('Section data:', data); setSectionData(data); setPageTitle(`${data.title} (${(data.tracks?.length || data.albums?.length || data.items?.length || 0)} items)`); } catch (error) { console.error('Error fetching section data:', error); setError(error instanceof Error ? error.message : 'Unknown error occurred'); } finally { setLoading(false); } }, [section, setPageTitle]); // Enhanced pull-to-refresh with desktop support and animated indicator const { containerRef, isRefreshing, pullDistance, refreshThreshold } = usePullToRefresh({ onRefresh: fetchSectionData }); // Restore scroll position per-section when navigating back useScrollRestore(containerRef as unknown as React.MutableRefObject, `section-more:${section ?? 'unknown'}`) // removed instructional text; use visual indicator + icon only useEffect(() => { if (section) { fetchSectionData(); } }, [section, fetchSectionData]); if (loading) { return (

{section ? section.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase()) : 'Section'}

); } if (error) { return (

{section ? section.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase()) : 'Section'}

Error: {error}

); } if (!sectionData || (!sectionData.tracks && !sectionData.albums && !sectionData.items) || (sectionData.tracks?.length === 0 && sectionData.albums?.length === 0 && sectionData.items?.length === 0)) { return (

{sectionData?.title || (section ? section.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase()) : 'Section')}

No data available for this section.

); } return (
{/* Pull indicator + relocated Refresh action inside the pull space */} {(pullDistance > 0 || isRefreshing) && (
)}

{sectionData.title}

{sectionData.description &&

{sectionData.description}

}
); };