Skip to content

Commit 1f680ef

Browse files
committed
feat: instant-hydrate GoalTracker from cached snapshot
- Load last cached goals list from localStorage on mount - Persist fresh goals to localStorage on successful load - Fall back to cached goals instead of an error message when the live fetch fails Closes #2801
1 parent 06a5a34 commit 1f680ef

1 file changed

Lines changed: 22 additions & 2 deletions

File tree

src/components/GoalTracker.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { buildPublicGoalShareUrl } from "@/lib/goals/share";
99
import GoalHistory from "@/components/GoalHistory";
1010
import EmptyState from "@/components/EmptyState";
1111
import WidgetSkeleton, { SkeletonBlock } from "./WidgetSkeleton";
12+
import { saveSnapshot, getSnapshot } from "@/lib/localCache";
1213

1314

1415
type Recurrence = "none" | "weekly" | "monthly";
@@ -90,9 +91,12 @@ export function useGoalTracker() {
9091
const data: { goals: Goal[] } = await response.json();
9192
const fetchedGoals = data.goals ?? [];
9293
setGoals(fetchedGoals);
94+
95+
// SWR: persist fresh snapshot for offline / instant-hydration use
96+
saveSnapshot("goals", fetchedGoals);
97+
9398
return fetchedGoals;
9499
}, []);
95-
96100
const handleSync = useCallback(async () => {
97101
setSyncing(true);
98102
setSyncError(null);
@@ -131,6 +135,15 @@ export function useGoalTracker() {
131135
}
132136
}, [loadGoals]);
133137

138+
// SWR Step 1: instant hydration from localStorage before network resolves
139+
useEffect(() => {
140+
const cached = getSnapshot<Goal[]>("goals");
141+
if (cached) {
142+
setGoals(cached.data);
143+
setLoading(false); // show stale goals immediately, no spinner
144+
}
145+
}, []);
146+
134147
useEffect(() => {
135148
loadGoals()
136149
.then(async (fetchedGoals) => {
@@ -145,7 +158,14 @@ export function useGoalTracker() {
145158
}
146159
})
147160
.catch(() => {
148-
setSyncError("Failed to load goals. Please try again.");
161+
// SWR fallback: agar live fetch fail ho, cached snapshot dikhta rahe
162+
const cached = getSnapshot<Goal[]>("goals");
163+
if (cached) {
164+
setGoals(cached.data);
165+
setSyncError(null);
166+
} else {
167+
setSyncError("Failed to load goals. Please try again.");
168+
}
149169
})
150170
.finally(() => {
151171
setLoading(false);

0 commit comments

Comments
 (0)