import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { ArrowLeft, Eye, Lightbulb, MapPin, ScanLine, Shield, Star, Tag, Wifi } from "lucide-react"; import { Link, useParams } from "react-router-dom"; import { api, mutationId } from "../api/client"; import type { Device, DeviceState } from "../api/types"; import { RgbControlPanel } from "../components/RgbControlPanel"; import { RgbZoneControls } from "../components/RgbZoneControls"; import { useToast } from "../components/Toast"; import { Badge, Button, Card, CardHeader, ErrorPanel, LoadingGrid, PageHeader } from "../components/ui"; import { useI18n } from "../lib/i18n"; import { formatDate } from "../lib/utils"; export function DeviceDetailPage() { const { text } = useI18n(); const { deviceId = "" } = useParams(); const queryClient = useQueryClient(); const { notify } = useToast(); const query = useQuery({ queryKey: ["device", deviceId], queryFn: () => api(`/api/v1/devices/${deviceId}`), }); const command = useMutation({ mutationFn: (state: DeviceState) => api(`/api/v1/devices/${deviceId}/state`, { method: "POST", headers: { "Idempotency-Key": mutationId() }, body: JSON.stringify({ state }), }), onSuccess: () => { notify("Apparaat bijgewerkt."); void queryClient.invalidateQueries({ queryKey: ["device", deviceId] }); void queryClient.invalidateQueries({ queryKey: ["device-groups"] }); void queryClient.invalidateQueries({ queryKey: ["system"] }); }, onError: (error) => notify(error instanceof Error ? error.message : "Opdracht mislukt.", "danger"), }); const patch = useMutation({ mutationFn: (value: Record) => api(`/api/v1/devices/${deviceId}`, { method: "PATCH", body: JSON.stringify(value), }), onSuccess: (data) => { queryClient.setQueryData(["device", deviceId], data); notify("Apparaatinstelling opgeslagen."); }, }); const identify = useMutation({ mutationFn: () => api(`/api/v1/devices/${deviceId}/identify`, { method: "POST" }), onSuccess: () => notify("Identificatie afgerond."), }); const zoneCommand = useMutation({ mutationFn: ({ zoneIndex: targetZone, state }: { zoneIndex: number; state: DeviceState }) => api(`/api/v1/devices/${deviceId}/zones/${targetZone}/state`, { method: "POST", headers: { "Idempotency-Key": mutationId() }, body: JSON.stringify({ state }), }), onSuccess: () => { void queryClient.invalidateQueries({ queryKey: ["device", deviceId] }); void queryClient.invalidateQueries({ queryKey: ["device-groups"] }); void queryClient.invalidateQueries({ queryKey: ["system"] }); notify("Aura-zone bijgewerkt."); }, onError: (error) => notify(error instanceof Error ? error.message : "Aura-zone kon niet worden bijgewerkt.", "danger"), }); if (query.isLoading) return ; if (query.error || !query.data) return void query.refetch()} />; const device = query.data; return <> Terug naar apparaten } />
{device.online ? "Online" : "Offline"} {device.read_only ? Alleen lezen : null} {device.experimental ? Experimenteel : null} Laatst gezien {formatDate(device.last_detected_at)}
command.mutate(state)} />
Beheerder
{device.owner}
Locatie
{device.location || "Niet bekend"}
Leds
{device.led_count}
Serienummer
{device.serial || "Niet gemeld"}
patch.mutate({ favorite: value })} /> patch.mutate({ hidden: value })} /> patch.mutate({ read_only: value })} /> patch.mutate({ blocked: value })} danger />
{device.capabilities.per_zone && device.zones.length ?

Moederbord en Aura-addressables

Bedien elke zone afzonderlijk. LumaOps gebruikt automatisch de volledige header; hardware-effecten in de algemene bediening blijven controllerbreed.

zoneCommand.mutate({ zoneIndex, state })} />
: null}

Zones en capabilities

OpenRGB SDK-v5 inventory zonder write-side effects.

{device.zones.map((zone) =>

{zone.name}

{zone.led_count} leds · type {zone.type}

)}{!device.zones.length ?

Dit apparaat rapporteert geen zones.

: null}
; } function Toggle({ label, checked, onChange, danger = false }: { label: string; checked: boolean; onChange: (value: boolean) => void; danger?: boolean }) { return ; }