From a4997a5fbc65913b55f2215eb3b868693bd76c51 Mon Sep 17 00:00:00 2001 From: Adam Mathes Date: Sat, 14 Feb 2026 10:03:35 -0800 Subject: test: increase frontend coverage for Settings and improve FeedItem css --- frontend/coverage/src/components/FeedList.tsx.html | 620 ++++++++++++++++----- 1 file changed, 469 insertions(+), 151 deletions(-) (limited to 'frontend/coverage/src/components/FeedList.tsx.html') diff --git a/frontend/coverage/src/components/FeedList.tsx.html b/frontend/coverage/src/components/FeedList.tsx.html index ba7d81f..acb2ede 100644 --- a/frontend/coverage/src/components/FeedList.tsx.html +++ b/frontend/coverage/src/components/FeedList.tsx.html @@ -1,64 +1,68 @@ + - + + Code coverage report for src/components/FeedList.tsx - - - - -
-
-

- All files / - src/components FeedList.tsx -

-
-
- 91.66% - Statements - 22/24 -
- -
- 82.35% - Branches - 14/17 -
- -
- 100% - Functions - 8/8 -
- -
- 100% - Lines - 20/20 -
+ + + +
+
+

All files / src/components FeedList.tsx

+
+ +
+ 79.54% + Statements + 35/44 +
+ + +
+ 64.86% + Branches + 24/37 +
+ + +
+ 64.7% + Functions + 11/17 +
+ + +
+ 82.05% + Lines + 32/39 +
+ +

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

-
-
-

+    
+    
+
1 2 3 @@ -139,18 +143,153 @@ 78 79 80 -81  -  -  -  -  -  -11x -11x -11x -11x -  -11x +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  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +13x +13x +13x +13x +13x +13x +13x +13x +13x +13x +  +  +13x +  +  +13x +  +  +  +  +  +  +13x +2x +  +  +13x 6x   4x @@ -172,8 +311,56 @@       -11x -5x +13x +7x +  +6x +1x +  +  +6x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +    4x   @@ -191,7 +378,20 @@       -3x +  +  +  +  +  +  +2x +  +  +  +  +  +  +        @@ -207,7 +407,6 @@       -3x       @@ -216,107 +415,226 @@       +  +  +  +  +  +  +  +  +  +  +  +  +  +  +         
import { useEffect, useState } from 'react';
-import { Link } from 'react-router-dom';
+import { Link, useNavigate, useSearchParams, useLocation, useParams } from 'react-router-dom';
 import type { Feed, Category } from '../types';
 import './FeedList.css';
+import { apiFetch } from '../utils';
+ 
+export default function FeedList({
+  theme,
+  setTheme,
+  setSidebarVisible,
+}: {
+  theme: string;
+  setTheme: (t: string) => void;
+  setSidebarVisible: (visible: boolean) => void;
+}) {
+  const [feeds, setFeeds] = useState<Feed[]>([]);
+  const [tags, setTags] = useState<Category[]>([]);
+  const [loading, setLoading] = useState(true);
+  const [error, setError] = useState('');
+  const [feedsExpanded, setFeedsExpanded] = useState(false);
+  const [searchQuery, setSearchQuery] = useState('');
+  const navigate = useNavigate();
+  const [searchParams] = useSearchParams();
+  const location = useLocation();
+  const { feedId, tagName } = useParams();
+ 
+  const currentFilter =
+    searchParams.get('filter') ||
+    (location.pathname === '/' && !feedId && !tagName ? 'unread' : '');
+ 
+  const handleSearch = (e: React.FormEvent) => {
+    e.preventDefault();
+    if (searchQuery.trim()) {
+      navigate(`/?q=${encodeURIComponent(searchQuery.trim())}`);
+    }
+  };
+ 
+  const toggleFeeds = () => {
+    setFeedsExpanded(!feedsExpanded);
+  };
+ 
+  useEffect(() => {
+    Promise.all([
+      apiFetch('/api/feed/').then((res) => {
+        Iif (!res.ok) throw new Error('Failed to fetch feeds');
+        return res.json();
+      }),
+      apiFetch('/api/tag').then((res) => {
+        Iif (!res.ok) throw new Error('Failed to fetch tags');
+        return res.json();
+      }),
+    ])
+      .then(([feedsData, tagsData]) => {
+        setFeeds(feedsData);
+        setTags(tagsData);
+        setLoading(false);
+      })
+      .catch((err) => {
+        setError(err.message);
+        setLoading(false);
+      });
+  }, []);
  
-export default function FeedList() {
-    const [feeds, setFeeds] = useState<Feed[]>([]);
-    const [tags, setTags] = useState<Category[]>([]);
-    const [loading, setLoading] = useState(true);
-    const [error, setError] = useState('');
+  if (loading) return <div className="feed-list-loading">Loading feeds...</div>;
+  if (error) return <div className="feed-list-error">Error: {error}</div>;
  
-    useEffect(() => {
-        Promise.all([
-            fetch('/api/feed/').then(res => {
-                Iif (!res.ok) throw new Error('Failed to fetch feeds');
-                return res.json();
-            }),
-            fetch('/api/tag').then(res => {
-                Iif (!res.ok) throw new Error('Failed to fetch tags');
-                return res.json();
-            })
-        ])
-            .then(([feedsData, tagsData]) => {
-                setFeeds(feedsData);
-                setTags(tagsData);
-                setLoading(false);
-            })
-            .catch((err) => {
-                setError(err.message);
-                setLoading(false);
-            });
-    }, []);
+  const handleLogout = () => {
+    apiFetch('/api/logout', { method: 'POST' }).then(() => (window.location.href = '/v2/login'));
+  };
  
-    if (loading) return <div className="feed-list-loading">Loading feeds...</div>;
-    if (error) return <div className="feed-list-error">Error: {error}</div>;
+  return (
+    <div className="feed-list">
+      <h1 className="logo" onClick={() => setSidebarVisible(false)}>
+        🐱
+      </h1>
  
-    return (
-        <div className="feed-list">
-            <div className="filter-section">
-                <ul className="filter-list">
-                    <li><Link to="/?filter=unread">Unread</Link></li>
-                    <li><Link to="/?filter=all">All</Link></li>
-                    <li><Link to="/?filter=starred">Starred</Link></li>
-                </ul>
-            </div>
-            <div className="feed-section">
-                <h2>Feeds</h2>
-                {feeds.length === 0 ? (
-                    <p>No feeds found.</p>
-                ) : (
-                    <ul className="feed-list-items">
-                        {feeds.map((feed) => (
-                            <li key={feed._id} className="sidebar-feed-item">
-                                <Link to={`/feed/${feed._id}`} className="feed-title">
-                                    {feed.title || feed.url}
-                                </Link>
-                                {feed.category && <span className="feed-category">{feed.category}</span>}
-                            </li>
-                        ))}
-                    </ul>
-                )}
-            </div>
+      <div className="search-section">
+        <form onSubmit={handleSearch} className="search-form">
+          <input
+            type="search"
+            placeholder="search..."
+            value={searchQuery}
+            onChange={(e) => setSearchQuery(e.target.value)}
+            className="search-input"
+          />
+        </form>
+      </div>
  
-            {tags && tags.length > 0 && (
-                <div className="tag-section">
-                    <h2>Tags</h2>
-                    <ul className="tag-list-items">
-                        {tags.map((tag) => (
-                            <li key={tag.title} className="tag-item">
-                                <Link to={`/tag/${encodeURIComponent(tag.title)}`} className="tag-link">
-                                    {tag.title}
-                                </Link>
-                            </li>
-                        ))}
-                    </ul>
-                </div>
-            )}
+      <div className="filter-section">
+        <ul className="filter-list">
+          <li className="unread_filter">
+            <Link to="/?filter=unread" className={currentFilter === 'unread' ? 'active' : ''}>
+              unread
+            </Link>
+          </li>
+          <li className="all_filter">
+            <Link to="/?filter=all" className={currentFilter === 'all' ? 'active' : ''}>
+              all
+            </Link>
+          </li>
+          <li className="starred_filter">
+            <Link to="/?filter=starred" className={currentFilter === 'starred' ? 'active' : ''}>
+              starred
+            </Link>
+          </li>
+        </ul>
+      </div>
+ 
+      <div className="tag-section">
+        <h4 onClick={() => { }} className="section-header">
+          Tags
+        </h4>
+        <ul className="tag-list-items">
+          {tags.map((tag) => (
+            <li key={tag.title} className="tag-item">
+              <Link
+                to={`/tag/${encodeURIComponent(tag.title)}`}
+                className={`tag-link ${tagName === tag.title ? 'active' : ''}`}
+              >
+                {tag.title}
+              </Link>
+            </li>
+          ))}
+        </ul>
+      </div>
+ 
+      <div className="feed-section">
+        <h4 onClick={toggleFeeds} className="section-header">
+          Feeds
+        </h4>
+        {feedsExpanded &&
+          (feeds.length === 0 ? (
+            <p>No feeds found.</p>
+          ) : (
+            <ul className="feed-list-items">
+              {feeds.map((feed) => (
+                <li key={feed._id} className="sidebar-feed-item">
+                  <Link
+                    to={`/feed/${feed._id}`}
+                    className={`feed-title ${feedId === String(feed._id) ? 'active' : ''}`}
+                  >
+                    {feed.title || feed.url}
+                  </Link>
+                </li>
+              ))}
+            </ul>
+          ))}
+      </div>
+ 
+      <div className="nav-section">
+        <ul className="nav-list">
+          <li>
+            <Link to="/settings" className="nav-link">
+              settings
+            </Link>
+          </li>
+          <li>
+            <button onClick={handleLogout} className="logout-link">
+              logout
+            </button>
+          </li>
+        </ul>
+      </div>
+ 
+      <div className="theme-section">
+        <div className="theme-selector">
+          <button
+            onClick={() => setTheme('light')}
+            className={theme === 'light' ? 'active' : ''}
+            title="Light Theme"
+          >
+            ☀️
+          </button>
+          <button
+            onClick={() => setTheme('dark')}
+            className={theme === 'dark' ? 'active' : ''}
+            title="Dark Theme"
+          >
+            🌙
+          </button>
         </div>
-    );
+      </div>
+    </div>
+  );
 }
  
-
- -
- - - - - - - +
+
+ + + + + + + \ No newline at end of file -- cgit v1.2.3