From cba29e6aae637b04ff6eaf28f74bc15b6242b9ea Mon Sep 17 00:00:00 2001 From: Adam Mathes Date: Mon, 16 Feb 2026 19:37:50 -0800 Subject: Remove legacy V2 React frontend and update build/test scripts to focus on Vanilla JS (V3) --- .../coverage/src/components/FeedItems.tsx.html | 838 --------------------- 1 file changed, 838 deletions(-) delete mode 100644 frontend/coverage/src/components/FeedItems.tsx.html (limited to 'frontend/coverage/src/components/FeedItems.tsx.html') diff --git a/frontend/coverage/src/components/FeedItems.tsx.html b/frontend/coverage/src/components/FeedItems.tsx.html deleted file mode 100644 index 9811743..0000000 --- a/frontend/coverage/src/components/FeedItems.tsx.html +++ /dev/null @@ -1,838 +0,0 @@ - - - - - - Code coverage report for src/components/FeedItems.tsx - - - - - - - - - -
-
-

All files / src/components FeedItems.tsx

-
- -
- 89.23% - Statements - 116/130 -
- - -
- 76.19% - Branches - 64/84 -
- - -
- 87.09% - Functions - 27/31 -
- - -
- 89.07% - Lines - 106/119 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -151 -152 -153 -154 -155 -156 -157 -158 -159 -160 -161 -162 -163 -164 -165 -166 -167 -168 -169 -170 -171 -172 -173 -174 -175 -176 -177 -178 -179 -180 -181 -182 -183 -184 -185 -186 -187 -188 -189 -190 -191 -192 -193 -194 -195 -196 -197 -198 -199 -200 -201 -202 -203 -204 -205 -206 -207 -208 -209 -210 -211 -212 -213 -214 -215 -216 -217 -218 -219 -220 -221 -222 -223 -224 -225 -226 -227 -228 -229 -230 -231 -232 -233 -234 -235 -236 -237 -238 -239 -240 -241 -242 -243 -244 -245 -246 -247 -248 -249 -250 -251 -252  -  -  -  -  -  -  -  -36x -36x -36x -  -36x -36x -36x -36x -36x -36x -  -36x -11x -3x -  -8x -8x -  -11x -  -11x -11x -  -11x -2x -9x -1x -  -  -11x -3x -  -  -  -11x -11x -  -  -  -11x -  -11x -  -  -  -  -11x -11x -  -  -  -11x -11x -11x -  -  -11x -  -10x -  -  -10x -  -  -9x -3x -  -6x -  -9x -9x -9x -  -  -1x -1x -1x -  -  -  -36x -8x -8x -  -  -  -  -36x -5x -5x -5x -  -  -  -36x -2x -  -3x -  -2x -  -  -  -  -  -  -36x -1x -  -2x -  -1x -  -  -  -  -  -  -36x -31x -6x -  -6x -5x -5x -5x -5x -5x -1x -  -5x -  -  -  -  -5x -2x -  -  -5x -  -1x -  -  -  -  -  -  -  -1x -1x -1x -1x -  -1x -  -  -  -  -31x -31x -  -  -  -  -  -36x -  -31x -  -1x -  -1x -1x -1x -1x -1x -1x -  -  -  -  -  -  -  -  -  -31x -  -1x -1x -1x -  -  -  -  -  -  -31x -31x -31x -  -  -31x -31x -  -31x -31x -31x -  -  -  -  -36x -21x -  -20x -  -  -  -  -  -  -44x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - 
import { useEffect, useState } from 'react';
-import { useParams, useSearchParams } from 'react-router-dom';
-import type { Item } from '../types';
-import FeedItem from './FeedItem';
-import './FeedItems.css';
-import { apiFetch } from '../utils';
- 
-export default function FeedItems() {
-  const { feedId, tagName } = useParams<{ feedId: string; tagName: string }>();
-  const [searchParams] = useSearchParams();
-  const filterFn = searchParams.get('filter') || 'unread';
- 
-  const [items, setItems] = useState<Item[]>([]);
-  const [loading, setLoading] = useState(true);
-  const [loadingMore, setLoadingMore] = useState(false);
-  const [hasMore, setHasMore] = useState(true);
-  const [error, setError] = useState('');
-  const [selectedIndex, setSelectedIndex] = useState(-1);
- 
-  const fetchItems = (maxId?: string) => {
-    if (maxId) {
-      setLoadingMore(true);
-    } else {
-      setLoading(true);
-      setItems([]);
-    }
-    setError('');
- 
-    let url = '/api/stream';
-    const params = new URLSearchParams();
- 
-    if (feedId) {
-      params.append('feed_id', feedId);
-    } else if (tagName) {
-      params.append('tag', tagName);
-    }
- 
-    if (maxId) {
-      params.append('max_id', maxId);
-    }
- 
-    // Apply filters
-    const searchQuery = searchParams.get('q');
-    Iif (searchQuery) {
-      params.append('q', searchQuery);
-    }
- 
-    Iif (filterFn === 'all') {
-      params.append('read_filter', 'all');
-    I} else if (filterFn === 'starred') {
-      params.append('starred', 'true');
-      params.append('read_filter', 'all');
-    } else {
-      // default to unread
-      Eif (!searchQuery) {
-        params.append('read_filter', 'unread');
-      }
-    }
- 
-    const queryString = params.toString();
-    Eif (queryString) {
-      url += `?${queryString}`;
-    }
- 
-    apiFetch(url)
-      .then((res) => {
-        Iif (!res.ok) {
-          throw new Error('Failed to fetch items');
-        }
-        return res.json();
-      })
-      .then((data) => {
-        if (maxId) {
-          setItems((prev) => [...prev, ...data]);
-        } else {
-          setItems(data);
-        }
-        setHasMore(data.length > 0);
-        setLoading(false);
-        setLoadingMore(false);
-      })
-      .catch((err) => {
-        setError(err.message);
-        setLoading(false);
-        setLoadingMore(false);
-      });
-  };
- 
-  useEffect(() => {
-    fetchItems();
-    setSelectedIndex(-1);
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [feedId, tagName, filterFn, searchParams]);
- 
- 
-  const scrollToItem = (index: number) => {
-    const element = document.getElementById(`item-${index}`);
-    Eif (element) {
-      element.scrollIntoView({ behavior: 'auto', block: 'start' });
-    }
-  };
- 
-  const markAsRead = (item: Item) => {
-    const updatedItem = { ...item, read: true };
-    // Optimistic update
-    setItems((prevItems) => prevItems.map((i) => (i._id === item._id ? updatedItem : i)));
- 
-    apiFetch(`/api/item/${item._id}`, {
-      method: 'PUT',
-      headers: { 'Content-Type': 'application/json' },
-      body: JSON.stringify({ read: true, starred: item.starred }),
-    }).catch((err) => console.error('Failed to mark read', err));
-  };
- 
-  const toggleStar = (item: Item) => {
-    const updatedItem = { ...item, starred: !item.starred };
-    // Optimistic update
-    setItems((prevItems) => prevItems.map((i) => (i._id === item._id ? updatedItem : i)));
- 
-    apiFetch(`/api/item/${item._id}`, {
-      method: 'PUT',
-      headers: { 'Content-Type': 'application/json' },
-      body: JSON.stringify({ read: item.read, starred: !item.starred }),
-    }).catch((err) => console.error('Failed to toggle star', err));
-  };
- 
-  useEffect(() => {
-    const handleKeyDown = (e: KeyboardEvent) => {
-      Iif (items.length === 0) return;
- 
-      if (e.key === 'j') {
-        setSelectedIndex((prev) => {
-          const nextIndex = Math.min(prev + 1, items.length - 1);
-          Eif (nextIndex !== prev) {
-            const item = items[nextIndex];
-            if (!item.read) {
-              markAsRead(item);
-            }
-            scrollToItem(nextIndex);
-          }
- 
-          // If we're now on the last item and there are more items to load,
-          // trigger loading them so the next 'j' press will work
-          if (nextIndex === items.length - 1 && hasMore && !loadingMore) {
-            fetchItems(String(items[items.length - 1]._id));
-          }
- 
-          return nextIndex;
-        });
-      I} else if (e.key === 'k') {
-        setSelectedIndex((prev) => {
-          const nextIndex = Math.max(prev - 1, 0);
-          if (nextIndex !== prev) {
-            scrollToItem(nextIndex);
-          }
-          return nextIndex;
-        });
-      E} else if (e.key === 's') {
-        setSelectedIndex((currentIndex) => {
-          Eif (currentIndex >= 0 && currentIndex < items.length) {
-            toggleStar(items[currentIndex]);
-          }
-          return currentIndex;
-        });
-      }
-    };
- 
-    window.addEventListener('keydown', handleKeyDown);
-    return () => window.removeEventListener('keydown', handleKeyDown);
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [items, hasMore, loadingMore]);
- 
- 
- 
-  useEffect(() => {
-    // Observer for marking items as read
-    const itemObserver = new IntersectionObserver(
-      (entries) => {
-        entries.forEach((entry) => {
-          // If item is not intersecting and is above the viewport, it's been scrolled past
-          Eif (!entry.isIntersecting && entry.boundingClientRect.top < 0) {
-            const index = Number(entry.target.getAttribute('data-index'));
-            Eif (!isNaN(index) && index >= 0 && index < items.length) {
-              const item = items[index];
-              Eif (!item.read) {
-                markAsRead(item);
-              }
-            }
-          }
-        });
-      },
-      { root: null, threshold: 0 }
-    );
- 
-    // Observer for infinite scroll (less aggressive, must be fully visible)
-    const sentinelObserver = new IntersectionObserver(
-      (entries) => {
-        entries.forEach((entry) => {
-          Eif (entry.isIntersecting && !loadingMore && hasMore && items.length > 0) {
-            fetchItems(String(items[items.length - 1]._id));
-          }
-        });
-      },
-      { root: null, threshold: 1.0 }
-    );
- 
-    items.forEach((_, index) => {
-      const el = document.getElementById(`item-${index}`);
-      Eif (el) itemObserver.observe(el);
-    });
- 
-    const sentinel = document.getElementById('load-more-sentinel');
-    if (sentinel) sentinelObserver.observe(sentinel);
- 
-    return () => {
-      itemObserver.disconnect();
-      sentinelObserver.disconnect();
-    };
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [items, loadingMore, hasMore]);
- 
-  if (loading) return <div className="feed-items-loading">Loading items...</div>;
-  if (error) return <div className="feed-items-error">Error: {error}</div>;
- 
-  return (
-    <div className="feed-items">
-      {items.length === 0 ? (
-        <p>No items found.</p>
-      ) : (
-        <ul className="item-list">
-          {items.map((item, index) => (
-            <div
-              id={`item-${index}`}
-              key={item._id}
-              data-index={index}
-              data-selected={index === selectedIndex}
-              onClick={() => setSelectedIndex(index)}
-            >
-              <FeedItem item={item} />
-            </div>
-          ))}
-          {hasMore && (
-            <div id="load-more-sentinel" className="loading-more">
-              {loadingMore ? 'Loading more...' : ''}
-            </div>
-          )}
-        </ul>
-      )}
-    </div>
-  );
-}
- 
- -
-
- - - - - - - - \ No newline at end of file -- cgit v1.2.3