Implement dual-surface financials and db bootstrap

This commit is contained in:
2026-03-06 16:24:56 -05:00
parent 8e62c66677
commit 8b1fff4130
7 changed files with 1207 additions and 179 deletions

View File

@@ -104,6 +104,13 @@ export function useTaskNotificationsCenter(): UseTaskNotificationsCenterResult {
const invalidatedTerminalRef = useRef(new Set<string>());
const activeSnapshotRef = useRef<Task[]>([]);
const finishedSnapshotRef = useRef<Task[]>([]);
const [isDocumentVisible, setIsDocumentVisible] = useState(() => {
if (typeof document === 'undefined') {
return true;
}
return document.visibilityState === 'visible';
});
const applyTaskLocally = useCallback((task: Task) => {
setActiveTasks((prev) => prev.map((entry) => (entry.id === task.id ? task : entry)));
@@ -285,10 +292,54 @@ export function useTaskNotificationsCenter(): UseTaskNotificationsCenterResult {
}
}, [processSnapshots]);
useEffect(() => {
if (typeof document === 'undefined') {
return;
}
const onVisibilityChange = () => {
setIsDocumentVisible(document.visibilityState === 'visible');
};
document.addEventListener('visibilitychange', onVisibilityChange);
return () => document.removeEventListener('visibilitychange', onVisibilityChange);
}, []);
useEffect(() => {
let cancelled = false;
let activeTimer: ReturnType<typeof setTimeout> | null = null;
let terminalTimer: ReturnType<typeof setTimeout> | null = null;
let stableTerminalPolls = 0;
let previousTerminalSignature = '';
const nextActiveDelay = () => {
if (!isDocumentVisible) {
return 30_000;
}
const hasActiveTasks = activeSnapshotRef.current.length > 0;
if (isPopoverOpen || isDetailOpen || hasActiveTasks) {
return 2_000;
}
return 12_000;
};
const nextTerminalDelay = () => {
if (!isDocumentVisible) {
return 60_000;
}
if (isPopoverOpen || isDetailOpen) {
return 4_000;
}
if (finishedSnapshotRef.current.some((task) => isUnread(task))) {
return 15_000;
}
return stableTerminalPolls >= 2 ? 45_000 : 20_000;
};
const runActiveLoop = async () => {
if (cancelled) {
@@ -314,7 +365,7 @@ export function useTaskNotificationsCenter(): UseTaskNotificationsCenterResult {
// ignore transient polling failures
}
activeTimer = setTimeout(runActiveLoop, 2_000);
activeTimer = setTimeout(runActiveLoop, nextActiveDelay());
};
const runTerminalLoop = async () => {
@@ -337,11 +388,19 @@ export function useTaskNotificationsCenter(): UseTaskNotificationsCenterResult {
setHasLoadedFinished(true);
setFinishedTasks(response.tasks);
processSnapshots();
const signature = response.tasks.map((task) => taskSignature(task)).join('||');
if (signature === previousTerminalSignature) {
stableTerminalPolls += 1;
} else {
stableTerminalPolls = 0;
previousTerminalSignature = signature;
}
} catch {
// ignore transient polling failures
}
terminalTimer = setTimeout(runTerminalLoop, 4_000);
terminalTimer = setTimeout(runTerminalLoop, nextTerminalDelay());
};
void runActiveLoop();
@@ -356,7 +415,7 @@ export function useTaskNotificationsCenter(): UseTaskNotificationsCenterResult {
clearTimeout(terminalTimer);
}
};
}, [processSnapshots]);
}, [isDetailOpen, isDocumentVisible, isPopoverOpen, processSnapshots]);
const normalizedActiveTasks = useMemo(() => {
return activeTasks.filter((task) => ACTIVE_STATUSES.includes(task.status));