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(false); useEffect(() => { fetch('/api') .then(res => 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) { if (error.name === 'AbortError') { console.log('Fetch timed out for story:', newStory.id); } else { console.log('Fetch failed for story:', newStory.id, error); } setError(true); 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) => { setError(true); } ); }, [updateCache]); return (
QotNews {error &&
Connection error? Click to expand.

{error}

} {stories ?
{stories.map(x =>
source logo {x.title} ({sourceLink(x)})
{infoLine(x)}
)}
:

loading...

}
); } export default Feed;