Files
HaBit/lib/app-tab-data-cache.ts
Harkamal Randhawa d5e80ec380 Finish interrupted features: tab prefetch, pet viewport, and home logo.
Add shared quiz/habits tab cache with nav hover prefetch and AppDataPrefetcher,
make the pet screen fill and center the viewport, and point the HaBit logo to /.
2026-05-24 04:57:13 -06:00

123 lines
2.7 KiB
TypeScript

import type { AvatarCondition, DailyQuizSubmission } from "@/lib/avatar-state";
import type { DailyTask } from "@/lib/daily-tasks";
import { getDailyTasks } from "@/lib/daily-tasks";
import {
getAvatarConditionForToday,
getDailyEntryForToday,
hasCompletedDailyQuizToday,
} from "@/lib/daily-quiz-storage";
import { getCustomHabits, type Habit } from "@/lib/habits-storage";
import { getProfilePreferences } from "@/lib/profile-preferences-storage";
export type QuizTabData = {
submission: DailyQuizSubmission | null;
liveCondition: AvatarCondition | null;
};
export type HabitsTabData = {
dailyTasks: DailyTask[];
customHabits: Habit[];
focusTopic: string | null;
quizCompletedToday: boolean;
};
let quizCache: QuizTabData | null = null;
let habitsCache: HabitsTabData | null = null;
let quizInflight: Promise<QuizTabData> | null = null;
let habitsInflight: Promise<HabitsTabData> | null = null;
export function getCachedQuizTabData() {
return quizCache;
}
export function getCachedHabitsTabData() {
return habitsCache;
}
export function invalidateAppTabDataCache() {
quizCache = null;
habitsCache = null;
}
async function loadQuizTabData(): Promise<QuizTabData> {
const submission = await getDailyEntryForToday();
if (submission) {
return {
submission,
liveCondition: submission.condition,
};
}
return {
submission: null,
liveCondition: await getAvatarConditionForToday(),
};
}
async function loadHabitsTabData(): Promise<HabitsTabData> {
const [dailyTasks, customHabits, preferences, quizCompletedToday] =
await Promise.all([
getDailyTasks(),
getCustomHabits(),
getProfilePreferences(),
hasCompletedDailyQuizToday(),
]);
return {
dailyTasks,
customHabits,
focusTopic: preferences.focusTopic,
quizCompletedToday,
};
}
export async function prefetchQuizTabData(options?: { force?: boolean }) {
if (!options?.force && quizCache) {
return quizCache;
}
if (quizInflight) {
return quizInflight;
}
quizInflight = loadQuizTabData()
.then((data) => {
quizCache = data;
return data;
})
.finally(() => {
quizInflight = null;
});
return quizInflight;
}
export async function prefetchHabitsTabData(options?: { force?: boolean }) {
if (!options?.force && habitsCache) {
return habitsCache;
}
if (habitsInflight) {
return habitsInflight;
}
habitsInflight = loadHabitsTabData()
.then((data) => {
habitsCache = data;
return data;
})
.finally(() => {
habitsInflight = null;
});
return habitsInflight;
}
export async function prefetchAppTabData(options?: { force?: boolean }) {
await Promise.all([
prefetchQuizTabData(options),
prefetchHabitsTabData(options),
]);
}