generated from Dicken/dickendock
Commit 6: Adminbereich (TanStack Router, 8 Menüpunkte, Scan-Logs)
This commit is contained in:
34
apps/frontend/src/hooks/useBackendHealth.ts
Normal file
34
apps/frontend/src/hooks/useBackendHealth.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import type { HealthStatus } from "@launchpad/shared";
|
||||
|
||||
export function useBackendHealth() {
|
||||
const [health, setHealth] = useState<HealthStatus | null>(null);
|
||||
const [error, setError] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
async function check() {
|
||||
try {
|
||||
const res = await fetch("/api/health");
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
const data: HealthStatus = await res.json();
|
||||
if (!cancelled) {
|
||||
setHealth(data);
|
||||
setError(false);
|
||||
}
|
||||
} catch {
|
||||
if (!cancelled) setError(true);
|
||||
}
|
||||
}
|
||||
|
||||
check();
|
||||
const interval = setInterval(check, 10_000);
|
||||
return () => {
|
||||
cancelled = true;
|
||||
clearInterval(interval);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return { health, error };
|
||||
}
|
||||
17
apps/frontend/src/hooks/useCategories.ts
Normal file
17
apps/frontend/src/hooks/useCategories.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { Category } from "@launchpad/shared";
|
||||
|
||||
async function fetchCategories(): Promise<Category[]> {
|
||||
const res = await fetch("/api/categories");
|
||||
if (!res.ok) {
|
||||
throw new Error(`Kategorien konnten nicht geladen werden (HTTP ${res.status})`);
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export function useCategories() {
|
||||
return useQuery({
|
||||
queryKey: ["categories"],
|
||||
queryFn: fetchCategories,
|
||||
});
|
||||
}
|
||||
21
apps/frontend/src/hooks/useDevices.ts
Normal file
21
apps/frontend/src/hooks/useDevices.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { Device, Service } from "@launchpad/shared";
|
||||
|
||||
export interface DeviceWithServices extends Device {
|
||||
services: Service[];
|
||||
}
|
||||
|
||||
async function fetchDevices(): Promise<DeviceWithServices[]> {
|
||||
const res = await fetch("/api/devices");
|
||||
if (!res.ok) {
|
||||
throw new Error(`Geräte konnten nicht geladen werden (HTTP ${res.status})`);
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export function useDevices() {
|
||||
return useQuery({
|
||||
queryKey: ["devices"],
|
||||
queryFn: fetchDevices,
|
||||
});
|
||||
}
|
||||
18
apps/frontend/src/hooks/useLogs.ts
Normal file
18
apps/frontend/src/hooks/useLogs.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { ScanLogEntry } from "@launchpad/shared";
|
||||
|
||||
async function fetchLogs(): Promise<ScanLogEntry[]> {
|
||||
const res = await fetch("/api/logs");
|
||||
if (!res.ok) {
|
||||
throw new Error(`Logs konnten nicht geladen werden (HTTP ${res.status})`);
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export function useLogs() {
|
||||
return useQuery({
|
||||
queryKey: ["logs"],
|
||||
queryFn: fetchLogs,
|
||||
refetchInterval: 5000,
|
||||
});
|
||||
}
|
||||
22
apps/frontend/src/hooks/useTheme.ts
Normal file
22
apps/frontend/src/hooks/useTheme.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export type Theme = "light" | "dark";
|
||||
|
||||
export function useTheme(): [Theme, () => void] {
|
||||
const [theme, setTheme] = useState<Theme>(() => {
|
||||
if (typeof window === "undefined") return "dark";
|
||||
const stored = window.localStorage.getItem("launchpad-theme");
|
||||
if (stored === "light" || stored === "dark") return stored;
|
||||
return window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
? "dark"
|
||||
: "light";
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
document.documentElement.classList.toggle("dark", theme === "dark");
|
||||
window.localStorage.setItem("launchpad-theme", theme);
|
||||
}, [theme]);
|
||||
|
||||
const toggle = () => setTheme((t) => (t === "dark" ? "light" : "dark"));
|
||||
return [theme, toggle];
|
||||
}
|
||||
Reference in New Issue
Block a user