fitaiProto/apps/mobile/src/contexts/StatisticsContext.tsx
2026-03-11 06:07:16 +01:00

135 lines
3.8 KiB
TypeScript

import React, { createContext, useContext, useState, useCallback } from "react";
import { useUser, useAuth } from "@clerk/clerk-expo";
import { getUserStatistics } from "../api/statistics";
import type { UserStatisticsResponse } from "../api/types";
import log from "../utils/logger";
interface StatisticsContextValue {
statistics: UserStatisticsResponse | null;
loading: boolean;
error: Error | null;
refetchStatistics: () => Promise<void>;
forceRefresh: () => Promise<void>;
clearCache: () => void;
}
const StatisticsContext = createContext<StatisticsContextValue | undefined>(
undefined,
);
export function StatisticsProvider({
children,
}: {
children: React.ReactNode;
}) {
const { user } = useUser();
const { getToken } = useAuth();
const [statistics, setStatistics] = useState<UserStatisticsResponse | null>(
null,
);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<Error | null>(null);
const [lastFetchTime, setLastFetchTime] = useState<number>(0);
// Cache statistics for 30 seconds to avoid duplicate calls
const CACHE_DURATION = 30000; // 30 seconds
const refetchStatistics = useCallback(async () => {
if (!user?.id) return;
// Check if we have recent cached data
const now = Date.now();
if (statistics && now - lastFetchTime < CACHE_DURATION) {
log.debug("Using cached statistics", {
age: now - lastFetchTime,
cacheRemaining: CACHE_DURATION - (now - lastFetchTime),
});
return;
}
try {
setLoading(true);
setError(null);
log.debug("Fetching fresh statistics", { userId: user.id });
const token = await getToken();
const stats = await getUserStatistics(user.id, token);
setStatistics(stats);
setLastFetchTime(now);
log.debug("Statistics fetched and cached", {
userId: user.id,
hasWeeklyTrend: !!stats.weeklyTrend,
weeklyTrendLength: stats.weeklyTrend?.length || 0,
weeklyTrendSample: stats.weeklyTrend?.[0],
stats,
});
} catch (err) {
const error = err instanceof Error ? err : new Error(String(err));
log.error("Failed to fetch statistics", error);
setError(error);
} finally {
setLoading(false);
}
}, [user?.id, getToken, statistics, lastFetchTime]);
const clearCache = useCallback(() => {
setStatistics(null);
setLastFetchTime(0);
setError(null);
log.debug("Statistics cache cleared");
}, []);
const forceRefresh = useCallback(async () => {
if (!user?.id) return;
try {
setLoading(true);
setError(null);
log.debug("Force fetching statistics", { userId: user.id });
const token = await getToken();
const stats = await getUserStatistics(user.id, token);
setStatistics(stats);
setLastFetchTime(Date.now());
log.debug("Statistics force fetched and cached", {
userId: user.id,
hasWeeklyTrend: !!stats.weeklyTrend,
weeklyTrendLength: stats.weeklyTrend?.length || 0,
weeklyTrendSample: stats.weeklyTrend?.[0],
stats,
});
} catch (err) {
const error = err instanceof Error ? err : new Error(String(err));
log.error("Failed to force fetch statistics", error);
setError(error);
} finally {
setLoading(false);
}
}, [user?.id, getToken]);
return (
<StatisticsContext.Provider
value={{
statistics,
loading,
error,
refetchStatistics,
forceRefresh,
clearCache,
}}
>
{children}
</StatisticsContext.Provider>
);
}
export function useStatistics() {
const context = useContext(StatisticsContext);
if (context === undefined) {
throw new Error("useStatistics must be used within a StatisticsProvider");
}
return context;
}