// Fetch and display feeds async function fetchFeeds() { try { const response = await fetch('/feeds'); if (response.ok) { const feeds = await response.json(); return feeds; } else { console.error('Failed to load feeds:', response.status); return null; } } catch (error) { console.error('Error loading feeds:', error); return null; } } // Close any open feed menus function closeAllFeedMenus() { document.querySelectorAll('.feed-menu.show').forEach(menu => { menu.classList.remove('show'); }); } // Add click handler to close menus when clicking outside document.addEventListener('click', (e) => { if (!e.target.closest('.feed-menu') && !e.target.closest('.feed-menu-button')) { closeAllFeedMenus(); } }); function formatDate(dateStr) { if (!dateStr) return 'Not available'; const date = new Date(dateStr); return date.toLocaleString(); } function renderFeedEntries(entries) { const mainContent = document.querySelector('.main-content'); mainContent.innerHTML = ''; entries.forEach(entry => { const entryDiv = document.createElement('div'); entryDiv.className = 'feed-entry'; const title = document.createElement('h2'); title.className = 'feed-entry-title'; const titleLink = document.createElement('a'); titleLink.href = entry.link || '#'; titleLink.target = '_blank'; titleLink.textContent = entry.title; title.appendChild(titleLink); const meta = document.createElement('div'); meta.className = 'feed-entry-meta'; if (entry.published) { const published = document.createElement('span'); published.textContent = `Published: ${formatDate(entry.published)}`; meta.appendChild(published); } if (entry.updated) { const updated = document.createElement('span'); updated.textContent = `Updated: ${formatDate(entry.updated)}`; meta.appendChild(updated); } const summary = document.createElement('div'); summary.className = 'feed-entry-summary'; summary.textContent = entry.summary; entryDiv.appendChild(title); entryDiv.appendChild(meta); entryDiv.appendChild(summary); mainContent.appendChild(entryDiv); }); } function openFeed(feed) { const name = document.createElement('span'); name.className = 'feed-name'; name.textContent = feed.name; const spinner = document.createElement('div'); spinner.className = 'feed-spinner'; name.appendChild(spinner); name.onclick = async () => { name.classList.add('loading'); try { const response = await fetch(`/poll/${feed.feed_id}`, { method: 'POST' }); if (response.ok) { const data = await response.json(); console.log('Feed poll response:', data); renderFeedEntries(data.entries); } else { console.error('Failed to poll feed:', response.status); } } catch (error) { console.error('Error polling feed:', error); } finally { name.classList.remove('loading'); } }; const menuButton = document.createElement('button'); menuButton.className = 'feed-menu-button'; menuButton.innerHTML = '⋮'; menuButton.title = 'Feed options'; menuButton.onclick = (e) => { e.stopPropagation(); closeAllFeedMenus(); menu.classList.toggle('show'); }; const menu = document.createElement('div'); menu.className = 'feed-menu'; const deleteItem = document.createElement('a'); deleteItem.className = 'feed-menu-item delete'; deleteItem.textContent = 'Remove Feed'; deleteItem.onclick = async (e) => { e.stopPropagation(); if (confirm(`Are you sure you want to delete "${feed.name}"?`)) { try { const response = await fetch(`/feeds/${feed.feed_id}`, { method: 'DELETE', }); if (response.ok) { handleFeeds(); } else { console.error('Failed to delete feed:', response.status); } } catch (error) { console.error('Error deleting feed:', error); } } menu.classList.remove('show'); }; menu.appendChild(deleteItem); name.appendChild(menuButton); name.appendChild(menu); return name; } async function handleFeeds() { const feeds = await fetchFeeds(); const feedList = document.getElementById('feedList'); if (feeds) { feedList.innerHTML = ''; if (feeds.length === 0) { const emptyMessage = document.createElement('div'); emptyMessage.className = 'feed-empty'; emptyMessage.textContent = 'No feeds added yet'; feedList.appendChild(emptyMessage); } else { feeds.forEach(feed => { feedList.appendChild(openFeed(feed)); }); } } else { feedList.innerHTML = '