diff --git a/src/components/ActivityFeed.tsx b/src/components/ActivityFeed.tsx index 48e3312..b6d59bd 100644 --- a/src/components/ActivityFeed.tsx +++ b/src/components/ActivityFeed.tsx @@ -60,7 +60,7 @@ const isEventTypeArray = (data: unknown): data is EventType[] => { export default function ActivityFeed({ username }: { username: string }) { const [events, setEvents] = useState([]); const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); + const [error, setError] = useState(""); // 🕒 time ago function const getTimeAgo = (dateString: string) => { @@ -76,69 +76,53 @@ export default function ActivityFeed({ username }: { username: string }) { useEffect(() => { const fetchEvents = async () => { - try { - setLoading(true); - setError(null); - - const res = await fetch( - `https://api.github.com/users/${username}/events` - ); - - // ✅ Check HTTP response success - if (!res.ok) { - const isRateLimited = res.status === 403; - const errorData = await res.json().catch(() => ({})); - const errorMessage = - typeof errorData === "object" && - errorData !== null && - "message" in errorData && - typeof errorData.message === "string" - ? errorData.message - : `HTTP ${res.status}: Failed to fetch events`; - - throw new ActivityFeedError( - isRateLimited - ? "GitHub API rate limit exceeded. Try again later." - : errorMessage, - isRateLimited, - res.status + try { + setLoading(true); + setError(""); + + const res = await fetch( + `https://api.github.com/users/${username}/events` ); - } - const data = await res.json(); + // Handle GitHub API rate limit + if (res.status === 403) { + const remaining = + res.headers.get("X-RateLimit-Remaining") || "0"; - // ✅ Validate response structure matches EventType[] - if (!isEventTypeArray(data)) { - throw new ActivityFeedError( - "Invalid API response structure. Expected array of events.", - false, - 200 - ); - } + const reset = + res.headers.get("X-RateLimit-Reset"); - setEvents(data); - } catch (err) { - const fetchError: FetchError = { - message: "Failed to fetch activity. Please try again.", - isRateLimited: false, - }; - - // Handle ActivityFeedError instances - if (err instanceof ActivityFeedError) { - fetchError.message = err.message; - fetchError.isRateLimited = err.isRateLimited; - fetchError.statusCode = err.statusCode; - } else if (err instanceof Error) { - // Handle generic errors - fetchError.message = err.message || fetchError.message; - } + const resetTime = reset + ? new Date(Number(reset) * 1000).toLocaleTimeString() + : "Unknown"; - setError(fetchError); - console.error("ActivityFeed fetch error:", fetchError); - setEvents([]); - } finally { - setLoading(false); - } + setError( + `GitHub API rate limit exceeded. + Please try again after ${resetTime}. + Remaining Requests: ${remaining}` + ); + + setEvents([]); + setLoading(false); + return; + } + + if (!res.ok) { + throw new Error("Failed to fetch activity"); + } + + const data = await res.json(); + + setEvents(data); + } catch (err) { + console.error(err); + + setError( + "Something went wrong while fetching GitHub activity." + ); + } finally { + setLoading(false); + } }; fetchEvents(); @@ -149,9 +133,16 @@ export default function ActivityFeed({ username }: { username: string }) { return (
-

+

Activity Feed

+ + {error && ( +
+ {error} +
+ )} + {loading ? (

Loading activity...

@@ -172,7 +163,7 @@ export default function ActivityFeed({ username }: { username: string }) { )}
) : events.length === 0 ? ( -

No activity found

+

No activity found

) : ( events.slice(0, 10).map((event) => (
-

+

Live GitHub Activity