From aee026b141532c11f8eb315ca77cc23f663901ae Mon Sep 17 00:00:00 2001 From: Adam Mathes Date: Mon, 16 Feb 2026 08:34:05 -0800 Subject: Implement feed management in settings - Close NK-cuz8gh: v3 feed management - Add 'Manage Feeds' section to settings view in v3 UI - Implement deleteFeed and updateFeed helper functions - Add event listeners for deleting feeds and updating tags - Add tests for new functionality - Created NK-cdwj52 for bulk edit feature --- frontend-vanilla/src/main.ts | 80 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) (limited to 'frontend-vanilla/src/main.ts') diff --git a/frontend-vanilla/src/main.ts b/frontend-vanilla/src/main.ts index ba842f9..c0adb92 100644 --- a/frontend-vanilla/src/main.ts +++ b/frontend-vanilla/src/main.ts @@ -317,6 +317,25 @@ export function renderSettings() { +
+

Manage Feeds

+ +
+

Data Management

@@ -375,6 +394,43 @@ export function renderSettings() { } } }); + + // Feed Management Listeners + document.querySelectorAll('.delete-feed-btn').forEach(btn => { + btn.addEventListener('click', async (e) => { + const id = parseInt((e.target as HTMLElement).getAttribute('data-id')!); + if (confirm('Are you sure you want to delete this feed?')) { + await deleteFeed(id); + fetchFeeds(); + // re-render settings to remove the deleted feed from list + // delay slightly to allow feed fetch? No, fetchFeeds is async. + // We should await fetchFeeds before re-rendering? + // But fetchFeeds updates store, and store emits 'feeds-updated'. + // Does 'feeds-updated' re-render settings? + // No, 'feeds-updated' calls renderFeeds (the sidebar list). + // So we need to explicitly call renderSettings() to update the management list. + // But we should wait for fetchFeeds() to complete so store is updated. + // wait... fetchFeeds() is async but we don't await result in the listener above? + // Ah, fetchFeeds() returns Promise. + await fetchFeeds(); + renderSettings(); + } + }); + }); + + document.querySelectorAll('.update-feed-tag-btn').forEach(btn => { + btn.addEventListener('click', async (e) => { + const id = parseInt((e.target as HTMLElement).getAttribute('data-id')!); + const input = document.querySelector(`.feed-tag-input[data-id="${id}"]`) as HTMLInputElement; + const category = input.value.trim(); + await updateFeed(id, { category }); + // updateFeed returns boolean, assuming success + await fetchFeeds(); + await fetchTags(); + renderSettings(); // Update list to show persistence + alert('Feed updated'); + }); + }); } async function addFeed(url: string): Promise { @@ -414,6 +470,30 @@ async function importOPML(file: File): Promise { } } +export async function deleteFeed(id: number): Promise { + try { + const res = await apiFetch(`/api/feed/${id}`, { method: 'DELETE' }); + return res.ok; + } catch (err) { + console.error('Failed to delete feed', err); + return false; + } +} + +export async function updateFeed(id: number, updates: Partial): Promise { + try { + const res = await apiFetch('/api/feed', { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ ...updates, _id: id }) + }); + return res.ok; + } catch (err) { + console.error('Failed to update feed', err); + return false; + } +} + // --- Data Actions --- export async function toggleStar(id: number) { -- cgit v1.2.3