import React, { useState, useEffect } from 'react'; import { Link } from 'react-router-dom'; import { Helmet } from 'react-helmet'; import localForage from 'localforage'; import { sourceLink, infoLine, logos } from './utils.js'; function Feed({ updateCache }) { const [stories, setStories] = useState(() => JSON.parse(localStorage.getItem('stories')) || false); const [error, setError] = useState(''); useEffect(() => { fetch('/api') .then(res => { if (!res.ok) { throw new Error(`Server responded with ${res.status} ${res.statusText}`); } return res.json(); }) .then( async (result) => { const newApiStories = result.stories; const updated = !stories || !stories.length || stories[0].id !== newApiStories[0].id; console.log('New stories available:', updated); if (!updated) return; if (!stories || !stories.length) { setStories(newApiStories); localStorage.setItem('stories', JSON.stringify(newApiStories)); } let currentStories = Array.isArray(stories) ? [...stories] : []; for (const newStory of [...newApiStories].reverse()) { try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 10000); // 10-second timeout const storyRes = await fetch('/api/' + newStory.id, { signal: controller.signal }); clearTimeout(timeoutId); if (!storyRes.ok) throw new Error('Story fetch failed'); const storyResult = await storyRes.json(); const fullStory = storyResult.story; await localForage.setItem(fullStory.id, fullStory); console.log('Preloaded story:', fullStory.id, fullStory.title); updateCache(fullStory.id, fullStory); const existingStoryIndex = currentStories.findIndex(s => s.id === newStory.id); if (existingStoryIndex > -1) { currentStories.splice(existingStoryIndex, 1); } currentStories.unshift(newStory); } catch (error) { let errorMessage; if (error.name === 'AbortError') { errorMessage = `The request to fetch story '${newStory.title}' (${newStory.id}) timed out after 10 seconds. Your connection may be unstable.`; console.log('Fetch timed out for story:', newStory.id); } else { errorMessage = `An error occurred while fetching story '${newStory.title}' (${newStory.id}): ${error.toString()}`; console.log('Fetch failed for story:', newStory.id, error); } setError(errorMessage); break; } } const finalStories = currentStories.slice(0, newApiStories.length); const removedStories = currentStories.slice(newApiStories.length); for (const story of removedStories) { console.log('Removed story:', story.id, story.title); localForage.removeItem(story.id); } localStorage.setItem('stories', JSON.stringify(finalStories)); setStories(finalStories); }, (error) => { const errorMessage = `Failed to fetch the main story list from the API. Your connection may be down or the server might be experiencing issues. Error: ${error.toString()}`; setError(errorMessage); } ); }, [updateCache]); return (
{error}
loading...
}