Olympus/frontend/athena/app/knowledge/devices/[id]/page.tsx
2026-07-03 10:25:52 +02:00

85 lines
4.3 KiB
TypeScript

"use client";
import { useEffect, useMemo, useState } from "react";
import Link from "next/link";
import { useParams } from "next/navigation";
import { Download } from "lucide-react";
import DetailSection from "@/components/common/DetailSection";
import DocumentTypeBadge from "@/components/knowledge/DocumentTypeBadge";
import TagList from "@/components/knowledge/TagList";
import { buttonVariants } from "@/components/ui/button";
import { api } from "@/lib/api";
import type { KnowledgeDevice, KnowledgeDocument, KnowledgeNote } from "@/types/knowledge";
export default function KnowledgeDeviceDetailPage() {
const params = useParams<{ id: string }>();
const [device, setDevice] = useState<KnowledgeDevice | null>(null);
const [documents, setDocuments] = useState<KnowledgeDocument[]>([]);
const [notes, setNotes] = useState<KnowledgeNote[]>([]);
const [error, setError] = useState("");
useEffect(() => {
Promise.all([
api.get<KnowledgeDevice>(`/knowledge/devices/${params.id}`),
api.get<KnowledgeDocument[]>(`/knowledge/documents?device_id=${params.id}&limit=100`),
api.get<KnowledgeNote[]>(`/knowledge/notes?device_id=${params.id}&limit=100`),
]).then(([deviceResponse, documentResponse, noteResponse]) => {
setDevice(deviceResponse.data);
setDocuments(documentResponse.data);
setNotes(noteResponse.data);
}).catch(() => setError("Gerät konnte nicht geladen werden"));
}, [params.id]);
const yearRange = useMemo(() => {
if (!device) return "-";
if (!device.production_year_from && !device.production_year_to) return "-";
return `${device.production_year_from ?? "?"} - ${device.production_year_to ?? "?"}`;
}, [device]);
if (error) return <p className="text-red-600">{error}</p>;
if (!device) return <p className="text-slate-500">Gerät wird geladen...</p>;
return (
<div className="space-y-6">
<div>
<h1 className="text-3xl font-bold text-slate-950">{device.name}</h1>
<p className="mt-1 text-sm text-slate-500">{device.manufacturer.name}{device.model_number ? ` · ${device.model_number}` : ""}</p>
</div>
<DetailSection title="Stammdaten">
<dl className="grid gap-3 text-sm md:grid-cols-2">
<div><dt className="text-slate-500">Gerätetyp</dt><dd className="font-medium">{device.device_type || "-"}</dd></div>
<div><dt className="text-slate-500">Frequenzbereich</dt><dd className="font-medium">{device.frequency_range || "-"}</dd></div>
<div><dt className="text-slate-500">Baujahre</dt><dd className="font-medium">{yearRange}</dd></div>
<div><dt className="text-slate-500">Slug</dt><dd className="font-medium">{device.slug}</dd></div>
</dl>
{device.notes && <p className="mt-4 whitespace-pre-wrap text-sm text-slate-700">{device.notes}</p>}
</DetailSection>
<DetailSection title="Dokumente">
<div className="space-y-3">
{documents.map((document) => (
<div key={document.id} className="flex items-center justify-between gap-3 rounded-lg border p-3">
<div>
<Link href={`/knowledge/documents/${document.id}`} className="font-medium text-slate-950 hover:underline">{document.title}</Link>
<div className="mt-2 flex flex-wrap items-center gap-2"><DocumentTypeBadge type={document.document_type} /><TagList tags={document.tags} /></div>
</div>
{document.file_name && <Link href={`/api/knowledge/documents/${document.id}/download`} className={buttonVariants({ variant: "outline", size: "icon-sm" })} title="Download"><Download size={16} /></Link>}
</div>
))}
{documents.length === 0 && <p className="text-sm text-slate-500">Keine verknüpften Dokumente.</p>}
</div>
</DetailSection>
<DetailSection title="Notizen">
<div className="space-y-3">
{notes.map((note) => (
<div key={note.id} className="rounded-lg border p-3">
<p className="font-medium">{note.title}</p>
<p className="mt-1 whitespace-pre-wrap text-sm text-slate-600">{note.content}</p>
</div>
))}
{notes.length === 0 && <p className="text-sm text-slate-500">Keine verknüpften Notizen.</p>}
</div>
</DetailSection>
</div>
);
}