fix images not loading on initial library load

This commit is contained in:
Stefan Hardegger
2025-12-16 09:56:34 +01:00
parent 77aec8a849
commit ccfc07ac2a
2 changed files with 46 additions and 6 deletions

View File

@@ -2,7 +2,7 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { useRouter, useSearchParams } from 'next/navigation'; import { useRouter, useSearchParams } from 'next/navigation';
import { searchApi, storyApi, tagApi } from '../../lib/api'; import { searchApi, storyApi, tagApi, getCurrentLibraryId } from '../../lib/api';
import { Story, Tag, FacetCount, AdvancedFilters } from '../../types/api'; import { Story, Tag, FacetCount, AdvancedFilters } from '../../types/api';
import { Input } from '../../components/ui/Input'; import { Input } from '../../components/ui/Input';
import Button from '../../components/ui/Button'; import Button from '../../components/ui/Button';
@@ -27,6 +27,7 @@ export default function LibraryContent() {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [searchLoading, setSearchLoading] = useState(false); const [searchLoading, setSearchLoading] = useState(false);
const [randomLoading, setRandomLoading] = useState(false); const [randomLoading, setRandomLoading] = useState(false);
const [libraryReady, setLibraryReady] = useState(false);
// Persisted filter state (survives navigation within session) // Persisted filter state (survives navigation within session)
const [searchQuery, setSearchQuery] = useLibraryFilters<string>('searchQuery', ''); const [searchQuery, setSearchQuery] = useLibraryFilters<string>('searchQuery', '');
@@ -43,6 +44,45 @@ export default function LibraryContent() {
const [refreshTrigger, setRefreshTrigger] = useState(0); const [refreshTrigger, setRefreshTrigger] = useState(0);
const [urlParamsProcessed, setUrlParamsProcessed] = useState(false); const [urlParamsProcessed, setUrlParamsProcessed] = useState(false);
// Wait for library ID to be set before rendering images
useEffect(() => {
// Check if library ID has been loaded from AuthContext
const checkLibraryId = () => {
const libraryId = getCurrentLibraryId();
// Library ID is ready when it's not the default fallback
// The actual library ID should be a UUID or a specific value
if (libraryId && libraryId !== 'default') {
setLibraryReady(true);
}
};
// Check immediately
checkLibraryId();
// If not ready, poll until it is (with timeout)
if (!libraryReady) {
const checkInterval = setInterval(() => {
const libraryId = getCurrentLibraryId();
if (libraryId && libraryId !== 'default') {
setLibraryReady(true);
clearInterval(checkInterval);
}
}, 50); // Check every 50ms
// Clear interval after 5 seconds to prevent infinite polling
const timeout = setTimeout(() => {
clearInterval(checkInterval);
// If still not ready after timeout, assume 'default' is the correct library ID
setLibraryReady(true);
}, 5000);
return () => {
clearInterval(checkInterval);
clearTimeout(timeout);
};
}
}, [libraryReady]);
// Initialize filters from URL parameters // Initialize filters from URL parameters
useEffect(() => { useEffect(() => {
const tagsParam = searchParams.get('tags'); const tagsParam = searchParams.get('tags');
@@ -127,8 +167,8 @@ export default function LibraryContent() {
// Debounce search to avoid too many API calls // Debounce search to avoid too many API calls
useEffect(() => { useEffect(() => {
// Don't run search until URL parameters have been processed // Don't run search until URL parameters have been processed and library is ready
if (!urlParamsProcessed) return; if (!urlParamsProcessed || !libraryReady) return;
const debounceTimer = setTimeout(() => { const debounceTimer = setTimeout(() => {
const performSearch = async () => { const performSearch = async () => {
@@ -180,7 +220,7 @@ export default function LibraryContent() {
}, searchQuery ? 500 : 0); // Debounce search queries, but load immediately for filters/pagination }, searchQuery ? 500 : 0); // Debounce search queries, but load immediately for filters/pagination
return () => clearTimeout(debounceTimer); return () => clearTimeout(debounceTimer);
}, [searchQuery, selectedTags, sortOption, sortDirection, page, refreshTrigger, urlParamsProcessed, advancedFilters]); }, [searchQuery, selectedTags, sortOption, sortDirection, page, refreshTrigger, urlParamsProcessed, libraryReady, advancedFilters]);
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearchQuery(e.target.value); setSearchQuery(e.target.value);
@@ -246,7 +286,7 @@ export default function LibraryContent() {
setRefreshTrigger(prev => prev + 1); setRefreshTrigger(prev => prev + 1);
}; };
if (loading) { if (loading || !libraryReady) {
return ( return (
<div className="flex items-center justify-center py-20"> <div className="flex items-center justify-center py-20">
<LoadingSpinner size="lg" /> <LoadingSpinner size="lg" />

File diff suppressed because one or more lines are too long