first commit
This commit is contained in:
5
frontend/src/hooks/index.ts
Normal file
5
frontend/src/hooks/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from "./useAnalytics";
|
||||
export * from "./useDashboardConfig";
|
||||
export * from "./useHistoricalImport";
|
||||
export * from "./useRealtimeHistory";
|
||||
export * from "./useRealtimeSocket";
|
||||
26
frontend/src/hooks/useAnalytics.ts
Normal file
26
frontend/src/hooks/useAnalytics.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { api } from "../api/client";
|
||||
|
||||
export function useAnalytics(
|
||||
rangeKey: string,
|
||||
bucket: string,
|
||||
compare: string,
|
||||
enabled = true,
|
||||
options?: { start?: string; end?: string; publicKiosk?: boolean; compareRanges?: Array<{ start: string; end: string; label: string; key?: string }> },
|
||||
) {
|
||||
const production = useQuery({
|
||||
queryKey: ["analytics", rangeKey, bucket, compare, options?.start, options?.end, options?.publicKiosk, JSON.stringify(options?.compareRanges ?? [])],
|
||||
queryFn: () => api.getAnalytics(rangeKey, bucket, compare, options),
|
||||
staleTime: 60 * 1000,
|
||||
enabled,
|
||||
});
|
||||
|
||||
const distribution = useQuery({
|
||||
queryKey: ["distribution", rangeKey, bucket, options?.start, options?.end, options?.publicKiosk],
|
||||
queryFn: () => api.getDistribution(rangeKey, bucket, options),
|
||||
staleTime: 60 * 1000,
|
||||
enabled,
|
||||
});
|
||||
|
||||
return { production, distribution };
|
||||
}
|
||||
11
frontend/src/hooks/useDashboardConfig.ts
Normal file
11
frontend/src/hooks/useDashboardConfig.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { api } from "../api/client";
|
||||
|
||||
export function useDashboardConfig(enabled = true) {
|
||||
return useQuery({
|
||||
queryKey: ["dashboard-config"],
|
||||
queryFn: api.getConfig,
|
||||
staleTime: 5 * 60 * 1000,
|
||||
enabled,
|
||||
});
|
||||
}
|
||||
40
frontend/src/hooks/useHistoricalImport.ts
Normal file
40
frontend/src/hooks/useHistoricalImport.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { api } from "../api/client";
|
||||
import type { HistoricalStartPayload } from "../types";
|
||||
|
||||
export function useHistoricalImport(enabled = true) {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const status = useQuery({
|
||||
queryKey: ["historical-status"],
|
||||
queryFn: api.getHistoricalStatus,
|
||||
staleTime: 5 * 1000,
|
||||
enabled,
|
||||
refetchInterval: (query) => (query.state.data?.running ? 3000 : 15000),
|
||||
});
|
||||
|
||||
const start = useMutation({
|
||||
mutationFn: (payload: HistoricalStartPayload) => api.startHistoricalImport(payload),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({ queryKey: ["historical-status"] });
|
||||
await queryClient.invalidateQueries({ queryKey: ["analytics"] });
|
||||
await queryClient.invalidateQueries({ queryKey: ["distribution"] });
|
||||
},
|
||||
});
|
||||
|
||||
const syncNow = useMutation({
|
||||
mutationFn: api.syncHistoricalNow,
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({ queryKey: ["historical-status"] });
|
||||
},
|
||||
});
|
||||
|
||||
const cancel = useMutation({
|
||||
mutationFn: api.cancelHistoricalImport,
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({ queryKey: ["historical-status"] });
|
||||
},
|
||||
});
|
||||
|
||||
return { status, start, syncNow, cancel };
|
||||
}
|
||||
16
frontend/src/hooks/useRealtimeHistory.ts
Normal file
16
frontend/src/hooks/useRealtimeHistory.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { api } from "../api/client";
|
||||
|
||||
export function useRealtimeHistory(
|
||||
rangeKey: string,
|
||||
enabled = true,
|
||||
options?: { start?: string; end?: string; metrics?: string[]; publicKiosk?: boolean },
|
||||
) {
|
||||
return useQuery({
|
||||
queryKey: ["realtime-history", rangeKey, options?.start, options?.end, options?.metrics?.join(","), options?.publicKiosk],
|
||||
queryFn: () => api.getRealtimeHistory(rangeKey, options),
|
||||
staleTime: 20 * 1000,
|
||||
refetchInterval: options?.start || options?.end ? false : 30 * 1000,
|
||||
enabled,
|
||||
});
|
||||
}
|
||||
66
frontend/src/hooks/useRealtimeSocket.ts
Normal file
66
frontend/src/hooks/useRealtimeSocket.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { api } from "../api/client";
|
||||
import type { SnapshotPayload } from "../types";
|
||||
|
||||
const EMPTY_SNAPSHOT: SnapshotPayload = {
|
||||
hero_cards: [],
|
||||
kpis: {},
|
||||
strings: [],
|
||||
phases: [],
|
||||
status: [],
|
||||
faults: [],
|
||||
};
|
||||
|
||||
const POLL_MS = Number(import.meta.env.VITE_LIVE_POLL_MS ?? 8000);
|
||||
|
||||
export function useRealtimeSocket(enabled = true) {
|
||||
const [snapshot, setSnapshot] = useState<SnapshotPayload>(EMPTY_SNAPSHOT);
|
||||
const [connected, setConnected] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!enabled) {
|
||||
setSnapshot(EMPTY_SNAPSHOT);
|
||||
setConnected(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let isActive = true;
|
||||
let timer: number | null = null;
|
||||
|
||||
const poll = async () => {
|
||||
try {
|
||||
const data = await api.getRealtimeSnapshot();
|
||||
if (!isActive) {
|
||||
return;
|
||||
}
|
||||
setSnapshot(data);
|
||||
setConnected(true);
|
||||
} catch {
|
||||
if (isActive) {
|
||||
setConnected(false);
|
||||
}
|
||||
} finally {
|
||||
if (isActive) {
|
||||
timer = window.setTimeout(poll, POLL_MS);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void poll();
|
||||
|
||||
return () => {
|
||||
isActive = false;
|
||||
if (timer !== null) {
|
||||
window.clearTimeout(timer);
|
||||
}
|
||||
};
|
||||
}, [enabled]);
|
||||
|
||||
const lastUpdated = useMemo(() => snapshot.updated_at ?? null, [snapshot.updated_at]);
|
||||
|
||||
return {
|
||||
snapshot,
|
||||
connected,
|
||||
lastUpdated,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user