aboutsummaryrefslogtreecommitdiffhomepage
path: root/frontend/src/components/FeedList.tsx
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-02-14 11:52:56 +0900
committernsfisis <nsfisis@gmail.com>2026-02-14 11:53:08 +0900
commit2889b562e64993482bd13fd806af8ed0865bab8b (patch)
tree39400ac4d994fb33d2c544e7d4b9d98f8ecbd86a /frontend/src/components/FeedList.tsx
parente216c3bc97994b4172d15d52b46d5f6b75f35ea4 (diff)
downloadfeedaka-2889b562e64993482bd13fd806af8ed0865bab8b.tar.gz
feedaka-2889b562e64993482bd13fd806af8ed0865bab8b.tar.zst
feedaka-2889b562e64993482bd13fd806af8ed0865bab8b.zip
refactor: migrate API from GraphQL to REST (TypeSpec/OpenAPI)
Replace the entire GraphQL stack (gqlgen, urql, graphql-codegen) with a TypeSpec → OpenAPI 3.x pipeline using oapi-codegen for Go server stubs and openapi-fetch + openapi-typescript for the frontend client. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'frontend/src/components/FeedList.tsx')
-rw-r--r--frontend/src/components/FeedList.tsx50
1 files changed, 38 insertions, 12 deletions
diff --git a/frontend/src/components/FeedList.tsx b/frontend/src/components/FeedList.tsx
index 24bcfc7..a3ba124 100644
--- a/frontend/src/components/FeedList.tsx
+++ b/frontend/src/components/FeedList.tsx
@@ -1,18 +1,43 @@
-import { useQuery } from "urql";
-import { GetFeedsDocument } from "../graphql/generated/graphql";
+import { useCallback, useEffect, useState } from "react";
+import type { components } from "../api/generated";
+import { api } from "../services/api-client";
import { FeedItem } from "./FeedItem";
+type Feed = components["schemas"]["Feed"];
+
interface Props {
onFeedUnsubscribed?: () => void;
}
-const urqlContextFeed = { additionalTypenames: ["Feed"] };
-
export function FeedList({ onFeedUnsubscribed }: Props) {
- const [{ data, fetching, error }] = useQuery({
- query: GetFeedsDocument,
- context: urqlContextFeed,
- });
+ const [feeds, setFeeds] = useState<Feed[]>([]);
+ const [fetching, setFetching] = useState(true);
+ const [error, setError] = useState<string | null>(null);
+
+ const fetchFeeds = useCallback(async () => {
+ setFetching(true);
+ const { data } = await api.GET("/api/feeds");
+ if (data) {
+ setFeeds(data);
+ setError(null);
+ } else {
+ setError("Failed to load feeds");
+ }
+ setFetching(false);
+ }, []);
+
+ useEffect(() => {
+ fetchFeeds();
+ }, [fetchFeeds]);
+
+ const handleFeedUnsubscribed = () => {
+ fetchFeeds();
+ onFeedUnsubscribed?.();
+ };
+
+ const handleFeedChanged = () => {
+ fetchFeeds();
+ };
if (fetching) {
return (
@@ -24,11 +49,11 @@ export function FeedList({ onFeedUnsubscribed }: Props) {
if (error) {
return (
<div className="rounded-lg bg-red-50 p-4 text-sm text-red-600">
- Error: {error.message}
+ Error: {error}
</div>
);
}
- if (!data?.feeds || data.feeds.length === 0) {
+ if (feeds.length === 0) {
return (
<div className="py-8 text-center">
<p className="text-sm text-stone-400">No feeds added yet.</p>
@@ -38,11 +63,12 @@ export function FeedList({ onFeedUnsubscribed }: Props) {
return (
<div className="space-y-3">
- {data.feeds.map((feed) => (
+ {feeds.map((feed) => (
<FeedItem
key={feed.id}
feed={feed}
- onFeedUnsubscribed={onFeedUnsubscribed}
+ onFeedUnsubscribed={handleFeedUnsubscribed}
+ onFeedChanged={handleFeedChanged}
/>
))}
</div>