perf(app): reduce redundant data fetching

Share bounded database pools across API repositories, consolidate sync and chat queries, and make mobile refreshes cache-aware and foreground-aware.

Add focused regression coverage, client freshness documentation, and repository agent role configuration.
This commit is contained in:
jjbrunton committed 2026-08-29 21:47:27 +01:00
1 parent 9957fa43f2
commit c7ee8a4851
81 files changed
+4456 -1400

No files matched your search

+18 -8
View File
@@ -39,6 +39,7 @@ export default function MatchesScreen() {
fetchMatches,
markAllAsSeen,
isLoading,
isRefreshing,
hasMore,
isLoadingMore,
totalCount,
@@ -58,7 +59,9 @@ export default function MatchesScreen() {
fetchTheirTurnQuestions,
currentView,
setCurrentView,
ensureViewLoaded,
fetchPendingQuestions,
fetchArchivedMatches,
// Nudge state and methods
nudgeCooldownUntil,
isNudging,
@@ -118,14 +121,12 @@ export default function MatchesScreen() {
setShowTutorial(false);
};
// Load whichever view is showing, once. Returning to this tab reuses what is
// already cached; the sync poll refreshes it when the server reports a change,
// and pull-to-refresh remains the explicit way to force one.
useFocusEffect(
useCallback(() => {
fetchMatches(true);
// Also refresh pending questions when focused
fetchPendingQuestions();
fetchTheirTurnQuestions();
// Check nudge cooldown
checkNudgeCooldown();
ensureViewLoaded();
// Cleanup: mark matches as seen when leaving the screen (if on Complete tab)
return () => {
@@ -134,9 +135,15 @@ export default function MatchesScreen() {
state.markAllAsSeen();
}
};
}, [])
}, [ensureViewLoaded])
);
// The nudge cooldown only moves when this device sends a nudge, and sendNudge
// already records the new cooldown, so one read on mount is enough.
useEffect(() => {
void checkNudgeCooldown();
}, [checkNudgeCooldown]);
// Format cooldown remaining time
const formatCooldownTime = (cooldownUntil: Date): string => {
const now = new Date();
@@ -633,13 +640,16 @@ export default function MatchesScreen() {
refreshing={
currentView === 'pending' ? isLoadingPending :
currentView === 'their_turn' ? isLoadingTheirTurn :
isLoading
currentView === 'archived' ? isLoadingArchived :
isRefreshing
}
onRefresh={() => {
if (currentView === 'pending') {
fetchPendingQuestions();
} else if (currentView === 'their_turn') {
fetchTheirTurnQuestions();
} else if (currentView === 'archived') {
fetchArchivedMatches();
} else {
fetchMatches(true);
}