From 5a547c2d78430d7361b2a1ed62f17299b57a3bbb Mon Sep 17 00:00:00 2001 From: oomokaro1 Date: Fri, 23 Oct 2026 04:06:10 +0100 Subject: [PATCH 1/4] fix(rewards): surface fetchAll errors via error state fetchAll swallowed balance/history fetch failures with console.error, leaving the UI stuck on empty data with no error indication. Set the existing error state in the catch block and clear it on success. --- src/lib/hooks/use-rewards.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/hooks/use-rewards.ts b/src/lib/hooks/use-rewards.ts index b77ff8b..1c93675 100644 --- a/src/lib/hooks/use-rewards.ts +++ b/src/lib/hooks/use-rewards.ts @@ -116,9 +116,11 @@ export function useRewards() { setHistory(cached.history); setClaimables(cached.claimables); } + setError(null); } catch (e) { if (isAbortError(e)) return; console.error("Failed to fetch rewards:", e); + setError(e instanceof Error ? e.message : "Failed to fetch rewards"); } finally { setLoading(false); } From 2214acb869ffa7912fce16cfaea29787c53b774b Mon Sep 17 00:00:00 2001 From: oomokaro1 Date: Fri, 23 Oct 2026 04:06:21 +0100 Subject: [PATCH 2/4] fix(auth): return null from executeRefresh on refresh failure When token refresh failed and isTokenExpired returned false (e.g. JWT with no readable expiry), executeRefresh returned the stale token. Callers then retried with a dead token, creating a silent 401 loop. Return null so callers can disconnect instead. --- src/lib/api/auth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/api/auth.ts b/src/lib/api/auth.ts index 92f362a..e87c453 100644 --- a/src/lib/api/auth.ts +++ b/src/lib/api/auth.ts @@ -160,7 +160,7 @@ async function executeRefresh(refreshTokenStr: string): Promise { .getState() .setError("Session expired. Please reconnect your wallet."); } - return useAuthStore.getState().jwt; + return null; } finally { inFlightRefreshPromise = null; } From 50e0770b3fd17e512fe74373f540e854910dbf5d Mon Sep 17 00:00:00 2001 From: oomokaro1 Date: Fri, 23 Oct 2026 04:06:30 +0100 Subject: [PATCH 3/4] fix(courses): guard getCourseModules against missing modules array course.modules.sort() threw when the API omitted the modules field, crashing the module list page. Default to an empty array so missing modules return [] instead of throwing. --- src/lib/api/courses.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/api/courses.ts b/src/lib/api/courses.ts index 968b4d1..f5555ec 100644 --- a/src/lib/api/courses.ts +++ b/src/lib/api/courses.ts @@ -235,7 +235,7 @@ export async function getCourseModules( signal?: AbortSignal ): Promise { const course = await getCourse(courseId, jwt, signal); - return [...course.modules].sort((a, b) => a.order - b.order); + return [...(course.modules ?? [])].sort((a, b) => a.order - b.order); } /** From 9d04f13c63d0a92146d84d4b28e3c2cd88b8de7e Mon Sep 17 00:00:00 2001 From: oomokaro1 Date: Fri, 23 Oct 2026 04:06:40 +0100 Subject: [PATCH 4/4] fix(courses): surface enrollment fetch errors via error state fetchEnrollments swallowed failures with console.error, so users never knew their enrollment data failed to load. Set the error state in the catch block and clear it on a successful fetch. --- src/lib/hooks/use-courses.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib/hooks/use-courses.ts b/src/lib/hooks/use-courses.ts index 512f9b3..76b5229 100644 --- a/src/lib/hooks/use-courses.ts +++ b/src/lib/hooks/use-courses.ts @@ -178,9 +178,12 @@ export function useCourses() { try { const data = await loadEnrollments(jwt, controller.signal); setEnrollments(data); + setError(null); } catch (err) { if (isAbortError(err)) return; - console.error("Failed to fetch enrollments:", err); + setError( + err instanceof Error ? err.message : "Failed to fetch enrollments" + ); } }, [jwt, setEnrollments]);