aboutsummaryrefslogtreecommitdiffstats
path: root/frontend/src/components/Settings.tsx
diff options
context:
space:
mode:
authorAdam Mathes <adam@adammathes.com>2026-02-14 08:58:38 -0800
committerAdam Mathes <adam@adammathes.com>2026-02-14 08:58:38 -0800
commite3c379d069ffa9661561d25cdbf2f5894a2f8ee8 (patch)
tree24d0e9f5610dd9c8f873c5b78e6bc1c88d32840a /frontend/src/components/Settings.tsx
parent4b06155fbde91a1bef6361ef36efb28789861928 (diff)
downloadneko-e3c379d069ffa9661561d25cdbf2f5894a2f8ee8.tar.gz
neko-e3c379d069ffa9661561d25cdbf2f5894a2f8ee8.tar.bz2
neko-e3c379d069ffa9661561d25cdbf2f5894a2f8ee8.zip
Refactor: project structure, implement dependency injection, and align v2 UI with v1
Diffstat (limited to 'frontend/src/components/Settings.tsx')
-rw-r--r--frontend/src/components/Settings.tsx214
1 files changed, 108 insertions, 106 deletions
diff --git a/frontend/src/components/Settings.tsx b/frontend/src/components/Settings.tsx
index def8ffe..b4f6a3b 100644
--- a/frontend/src/components/Settings.tsx
+++ b/frontend/src/components/Settings.tsx
@@ -3,119 +3,121 @@ import type { Feed } from '../types';
import './Settings.css';
export default function Settings() {
- const [feeds, setFeeds] = useState<Feed[]>([]);
- const [newFeedUrl, setNewFeedUrl] = useState('');
- const [loading, setLoading] = useState(false);
- const [error, setError] = useState<string | null>(null);
+ const [feeds, setFeeds] = useState<Feed[]>([]);
+ const [newFeedUrl, setNewFeedUrl] = useState('');
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState<string | null>(null);
- useEffect(() => {
- fetchFeeds();
- }, []);
+ const fetchFeeds = () => {
+ setLoading(true);
+ fetch('/api/feed/')
+ .then((res) => {
+ if (!res.ok) throw new Error('Failed to fetch feeds');
+ return res.json();
+ })
+ .then((data) => {
+ setFeeds(data);
+ setLoading(false);
+ })
+ .catch((err) => {
+ setError(err.message);
+ setLoading(false);
+ });
+ };
- const fetchFeeds = () => {
- setLoading(true);
- fetch('/api/feed/')
- .then((res) => {
- if (!res.ok) throw new Error('Failed to fetch feeds');
- return res.json();
- })
- .then((data) => {
- setFeeds(data);
- setLoading(false);
- })
- .catch((err) => {
- setError(err.message);
- setLoading(false);
- });
- };
+ useEffect(() => {
+ fetchFeeds();
+ }, []);
- const handleAddFeed = (e: React.FormEvent) => {
- e.preventDefault();
- if (!newFeedUrl) return;
- setLoading(true);
- fetch('/api/feed/', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ url: newFeedUrl }),
- })
- .then((res) => {
- if (!res.ok) throw new Error('Failed to add feed');
- return res.json();
- })
- .then(() => {
- setNewFeedUrl('');
- fetchFeeds(); // Refresh list (or we could append if server returns full feed object)
- })
- .catch((err) => {
- setError(err.message);
- setLoading(false);
- });
- };
- const handleDeleteFeed = (id: number) => {
- if (!globalThis.confirm('Are you sure you want to delete this feed?')) return;
+ const handleAddFeed = (e: React.FormEvent) => {
+ e.preventDefault();
+ if (!newFeedUrl) return;
- setLoading(true);
- fetch(`/api/feed/${id}`, {
- method: 'DELETE',
- })
- .then((res) => {
- if (!res.ok) throw new Error('Failed to delete feed');
- setFeeds(feeds.filter((f) => f._id !== id));
- setLoading(false);
- })
- .catch((err) => {
- setError(err.message);
- setLoading(false);
- });
- };
+ setLoading(true);
+ fetch('/api/feed/', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ url: newFeedUrl }),
+ })
+ .then((res) => {
+ if (!res.ok) throw new Error('Failed to add feed');
+ return res.json();
+ })
+ .then(() => {
+ setNewFeedUrl('');
+ fetchFeeds(); // Refresh list (or we could append if server returns full feed object)
+ })
+ .catch((err) => {
+ setError(err.message);
+ setLoading(false);
+ });
+ };
- return (
- <div className="settings-page">
- <h2>Settings</h2>
+ const handleDeleteFeed = (id: number) => {
+ if (!globalThis.confirm('Are you sure you want to delete this feed?')) return;
- <div className="add-feed-section">
- <h3>Add New Feed</h3>
- <form onSubmit={handleAddFeed} className="add-feed-form">
- <input
- type="url"
- value={newFeedUrl}
- onChange={(e) => setNewFeedUrl(e.target.value)}
- placeholder="https://example.com/feed.xml"
- required
- className="feed-input"
- disabled={loading}
- />
- <button type="submit" disabled={loading}>
- Add Feed
- </button>
- </form>
- {error && <p className="error-message">{error}</p>}
- </div>
+ setLoading(true);
+ fetch(`/api/feed/${id}`, {
+ method: 'DELETE',
+ })
+ .then((res) => {
+ if (!res.ok) throw new Error('Failed to delete feed');
+ setFeeds(feeds.filter((f) => f._id !== id));
+ setLoading(false);
+ })
+ .catch((err) => {
+ setError(err.message);
+ setLoading(false);
+ });
+ };
- <div className="feed-list-section">
- <h3>Manage Feeds</h3>
- {loading && <p>Loading...</p>}
- <ul className="settings-feed-list">
- {feeds.map((feed) => (
- <li key={feed._id} className="settings-feed-item">
- <div className="feed-info">
- <span className="feed-title">{feed.title || '(No Title)'}</span>
- <span className="feed-url">{feed.url}</span>
- </div>
- <button
- onClick={() => handleDeleteFeed(feed._id)}
- className="delete-btn"
- disabled={loading}
- title="Delete Feed"
- >
- Delete
- </button>
- </li>
- ))}
- </ul>
- </div>
- </div>
- );
+ return (
+ <div className="settings-page">
+ <h2>Settings</h2>
+
+ <div className="add-feed-section">
+ <h3>Add New Feed</h3>
+ <form onSubmit={handleAddFeed} className="add-feed-form">
+ <input
+ type="url"
+ value={newFeedUrl}
+ onChange={(e) => setNewFeedUrl(e.target.value)}
+ placeholder="https://example.com/feed.xml"
+ required
+ className="feed-input"
+ disabled={loading}
+ />
+ <button type="submit" disabled={loading}>
+ Add Feed
+ </button>
+ </form>
+ {error && <p className="error-message">{error}</p>}
+ </div>
+
+ <div className="feed-list-section">
+ <h3>Manage Feeds</h3>
+ {loading && <p>Loading...</p>}
+ <ul className="settings-feed-list">
+ {feeds.map((feed) => (
+ <li key={feed._id} className="settings-feed-item">
+ <div className="feed-info">
+ <span className="feed-title">{feed.title || '(No Title)'}</span>
+ <span className="feed-url">{feed.url}</span>
+ </div>
+ <button
+ onClick={() => handleDeleteFeed(feed._id)}
+ className="delete-btn"
+ disabled={loading}
+ title="Delete Feed"
+ >
+ Delete
+ </button>
+ </li>
+ ))}
+ </ul>
+ </div>
+ </div>
+ );
}