chore(repo): initialize planarchy workspace

This commit is contained in:
2026-03-14 14:31:09 +01:00
commit dd55d0e78b
769 changed files with 166461 additions and 0 deletions
+69
View File
@@ -0,0 +1,69 @@
"use client";
import { SSE_EVENT_TYPES } from "@planarchy/shared";
import { useQueryClient } from "@tanstack/react-query";
import { useEffect, useRef } from "react";
/**
* Connects to the SSE timeline endpoint and invalidates React Query caches
* when allocation/project change events arrive.
*/
export function useTimelineSSE() {
const queryClient = useQueryClient();
const reconnectTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(() => {
let es: EventSource | null = null;
let reconnectAttempts = 0;
function connect() {
es = new EventSource("/api/sse/timeline");
es.onmessage = (event) => {
try {
const data = JSON.parse(event.data as string) as { type: string };
switch (data.type) {
case SSE_EVENT_TYPES.ALLOCATION_CREATED:
case SSE_EVENT_TYPES.ALLOCATION_UPDATED:
case SSE_EVENT_TYPES.ALLOCATION_DELETED:
void queryClient.invalidateQueries({ queryKey: [["timeline", "getEntries"]] });
void queryClient.invalidateQueries({ queryKey: [["allocation", "list"]] });
break;
case SSE_EVENT_TYPES.PROJECT_SHIFTED:
void queryClient.invalidateQueries({ queryKey: [["timeline", "getEntries"]] });
void queryClient.invalidateQueries({ queryKey: [["project", "list"]] });
break;
case SSE_EVENT_TYPES.BUDGET_WARNING:
void queryClient.invalidateQueries({ queryKey: [["timeline", "getBudgetStatus"]] });
break;
case SSE_EVENT_TYPES.PING:
reconnectAttempts = 0; // Reset on successful ping
break;
}
} catch {
// Ignore parse errors
}
};
es.onerror = () => {
es?.close();
reconnectAttempts++;
const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), 30000);
reconnectTimeout.current = setTimeout(connect, delay);
};
}
connect();
return () => {
es?.close();
if (reconnectTimeout.current) {
clearTimeout(reconnectTimeout.current);
}
};
}, [queryClient]);
}