"use client"; import Link from "next/link"; import { useParams } from "next/navigation"; import { FormEvent, useEffect, useMemo, useState } from "react"; import { copyGlobalDeviceToProject, copyProjectDeviceToGlobal, createDistributionBoard, createFloor, createProjectDevice, createRoom, deleteProjectDevice, listDistributionBoards, listFloors, listGlobalDevices, listProjectDevices, listProjects, listRooms, updateProjectDevice, updateProjectSettings, } from "../../../frontend/utils/api"; import type { CreateProjectDeviceInput, DistributionBoardDto, FloorDto, GlobalDeviceDto, ProjectDeviceDto, ProjectDto, RoomDto, } from "../../../frontend/types"; const emptyProjectDevice: CreateProjectDeviceInput = { name: "", displayName: "", category: "", quantity: 1, installedPowerPerUnitKw: 0.1, demandFactor: 1, voltageV: 230, phaseCount: 1, powerFactor: 1, note: "", }; function toOptionalNumber(value: string) { const trimmed = value.trim(); if (!trimmed) { return undefined; } return Number(trimmed); } export default function ProjectDetailPage() { const params = useParams<{ projectId: string }>(); const [projectId, setProjectId] = useState(""); const [project, setProject] = useState(null); const [boards, setBoards] = useState([]); const [floors, setFloors] = useState([]); const [rooms, setRooms] = useState([]); const [projectDevices, setProjectDevices] = useState([]); const [globalDevices, setGlobalDevices] = useState([]); const [boardName, setBoardName] = useState(""); const [floorName, setFloorName] = useState(""); const [roomNumber, setRoomNumber] = useState(""); const [roomName, setRoomName] = useState(""); const [roomFloorId, setRoomFloorId] = useState(""); const [singlePhaseVoltageV, setSinglePhaseVoltageV] = useState("230"); const [threePhaseVoltageV, setThreePhaseVoltageV] = useState("400"); const [projectDeviceForm, setProjectDeviceForm] = useState>({ name: "", displayName: "", category: "", quantity: "1", installedPowerPerUnitKw: "0.1", demandFactor: "1", voltageV: "230", phaseCount: "1", powerFactor: "1", note: "", }); const [selectedGlobalDeviceId, setSelectedGlobalDeviceId] = useState(""); const [error, setError] = useState(null); const [isSaving, setIsSaving] = useState(false); useEffect(() => { setProjectId(params.projectId); }, [params.projectId]); useEffect(() => { if (!projectId) { return; } Promise.all([ listProjects(), listDistributionBoards(projectId), listFloors(projectId), listRooms(projectId), listProjectDevices(projectId), listGlobalDevices(), ]) .then(([projects, distributionBoards, loadedFloors, loadedRooms, loadedProjectDevices, loadedGlobalDevices]) => { const currentProject = projects.find((item) => item.id === projectId) ?? null; setProject(currentProject); if (currentProject) { setSinglePhaseVoltageV(String(currentProject.singlePhaseVoltageV)); setThreePhaseVoltageV(String(currentProject.threePhaseVoltageV)); } setBoards(distributionBoards); setFloors(loadedFloors); setRooms(loadedRooms); setProjectDevices(loadedProjectDevices); setGlobalDevices(loadedGlobalDevices); setError(null); }) .catch((err: unknown) => setError(err instanceof Error ? err.message : "Projektdaten konnten nicht geladen werden.") ); }, [projectId]); const boardCount = useMemo(() => boards.length, [boards.length]); const floorCount = useMemo(() => floors.length, [floors.length]); const roomCount = useMemo(() => rooms.length, [rooms.length]); const projectDeviceCount = useMemo(() => projectDevices.length, [projectDevices.length]); const floorById = useMemo(() => new Map(floors.map((item) => [item.id, item])), [floors]); async function handleCreateBoard(event: FormEvent) { event.preventDefault(); if (!projectId || !boardName.trim()) { return; } setIsSaving(true); setError(null); try { const created = await createDistributionBoard(projectId, boardName.trim()); setBoards((current) => [...current, created]); setBoardName(""); } catch (err) { setError(err instanceof Error ? err.message : "Verteilung konnte nicht erstellt werden."); } finally { setIsSaving(false); } } async function handleCreateFloor(event: FormEvent) { event.preventDefault(); if (!projectId || !floorName.trim()) { return; } setIsSaving(true); setError(null); try { const created = await createFloor(projectId, { name: floorName.trim() }); setFloors((current) => [...current, created]); setFloorName(""); } catch (err) { setError(err instanceof Error ? err.message : "Etage konnte nicht erstellt werden."); } finally { setIsSaving(false); } } async function handleCreateRoom(event: FormEvent) { event.preventDefault(); if (!projectId || !roomNumber.trim() || !roomName.trim()) { return; } setIsSaving(true); setError(null); try { const created = await createRoom(projectId, { floorId: roomFloorId || undefined, roomNumber: roomNumber.trim(), roomName: roomName.trim(), }); setRooms((current) => [...current, created]); setRoomNumber(""); setRoomName(""); setRoomFloorId(""); } catch (err) { setError(err instanceof Error ? err.message : "Raum konnte nicht erstellt werden."); } finally { setIsSaving(false); } } async function handleSaveProjectSettings() { if (!projectId) { return; } setIsSaving(true); setError(null); try { const updated = await updateProjectSettings(projectId, { singlePhaseVoltageV: Number(singlePhaseVoltageV), threePhaseVoltageV: Number(threePhaseVoltageV), }); setProject(updated); } catch (err) { setError(err instanceof Error ? err.message : "Projekteigenschaften konnten nicht gespeichert werden."); } finally { setIsSaving(false); } } async function handleCreateProjectDevice(event: FormEvent) { event.preventDefault(); if (!projectId || !projectDeviceForm.name.trim()) { return; } const payload: CreateProjectDeviceInput = { name: projectDeviceForm.name.trim(), displayName: projectDeviceForm.displayName.trim() || projectDeviceForm.name.trim(), category: projectDeviceForm.category.trim() || undefined, quantity: Number(projectDeviceForm.quantity), installedPowerPerUnitKw: Number(projectDeviceForm.installedPowerPerUnitKw), demandFactor: Number(projectDeviceForm.demandFactor), voltageV: toOptionalNumber(projectDeviceForm.voltageV), phaseCount: projectDeviceForm.phaseCount === "3" ? 3 : 1, powerFactor: toOptionalNumber(projectDeviceForm.powerFactor), note: projectDeviceForm.note.trim() || undefined, }; setIsSaving(true); setError(null); try { const created = await createProjectDevice(projectId, payload); setProjectDevices((current) => [...current, created]); setProjectDeviceForm({ name: emptyProjectDevice.name, displayName: emptyProjectDevice.displayName, category: emptyProjectDevice.category ?? "", quantity: String(emptyProjectDevice.quantity), installedPowerPerUnitKw: String(emptyProjectDevice.installedPowerPerUnitKw), demandFactor: String(emptyProjectDevice.demandFactor), voltageV: String(emptyProjectDevice.voltageV ?? ""), phaseCount: String(emptyProjectDevice.phaseCount ?? 1), powerFactor: String(emptyProjectDevice.powerFactor ?? ""), note: emptyProjectDevice.note ?? "", }); } catch (err) { setError(err instanceof Error ? err.message : "Projektgerät konnte nicht erstellt werden."); } finally { setIsSaving(false); } } async function handleDeleteProjectDevice(projectDeviceId: string) { if (!projectId) { return; } setIsSaving(true); setError(null); try { await deleteProjectDevice(projectId, projectDeviceId); setProjectDevices((current) => current.filter((item) => item.id !== projectDeviceId)); } catch (err) { setError(err instanceof Error ? err.message : "Projektgerät konnte nicht gelöscht werden."); } finally { setIsSaving(false); } } async function handleQuickUpdateProjectDevice( device: ProjectDeviceDto, key: "name" | "displayName" | "category", value: string ) { if (!projectId) { return; } const payload: CreateProjectDeviceInput = { name: key === "name" ? value : device.name, displayName: key === "displayName" ? value : device.displayName, category: key === "category" ? value : device.category ?? undefined, quantity: device.quantity, installedPowerPerUnitKw: device.installedPowerPerUnitKw, demandFactor: device.demandFactor, voltageV: device.voltageV ?? undefined, phaseCount: device.phaseCount ?? undefined, powerFactor: device.powerFactor ?? undefined, note: device.note ?? undefined, }; try { const updated = await updateProjectDevice(projectId, device.id, payload); setProjectDevices((current) => current.map((item) => (item.id === device.id ? updated : item))); } catch (err) { setError(err instanceof Error ? err.message : "Projektgerät konnte nicht aktualisiert werden."); } } async function handleCopyGlobalToProject() { if (!projectId || !selectedGlobalDeviceId) { return; } setIsSaving(true); setError(null); try { const created = await copyGlobalDeviceToProject(projectId, selectedGlobalDeviceId); setProjectDevices((current) => [...current, created]); } catch (err) { setError(err instanceof Error ? err.message : "Globales Gerät konnte nicht ins Projekt kopiert werden."); } finally { setIsSaving(false); } } async function handleCopyProjectToGlobal(projectDeviceId: string) { if (!projectId) { return; } setIsSaving(true); setError(null); try { const created = await copyProjectDeviceToGlobal(projectId, projectDeviceId); setGlobalDevices((current) => [...current, created]); } catch (err) { setError(err instanceof Error ? err.message : "Projektgerät konnte nicht global kopiert werden."); } finally { setIsSaving(false); } } return (

{project?.name ?? "Projekt"}

Verteilerübersicht und Einstieg in die Stromkreislisten

Zur Projektseite
{error ?
{error}
: null}
Projekteigenschaften
setSinglePhaseVoltageV(event.target.value)} />
setThreePhaseVoltageV(event.target.value)} />
Neue Verteilung
setBoardName(event.target.value)} />
Alle Verteilungen {boardCount}
{boards.map((board) => ( ))} {!boards.length ? ( ) : null}
Verteilung Aktionen
{board.name} Stromkreisliste öffnen
Noch keine Verteilungen vorhanden.
Etagen {floorCount}
setFloorName(event.target.value)} />
    {floors.map((floor) => (
  • {floor.name}
  • ))} {!floors.length ? (
  • Noch keine Etagen vorhanden.
  • ) : null}
Räume {roomCount}
setRoomNumber(event.target.value)} />
setRoomName(event.target.value)} />
{rooms.map((room) => ( ))} {!rooms.length ? ( ) : null}
Raumnummer Raumname Etage
{room.roomNumber} {room.roomName} {room.floorId ? floorById.get(room.floorId)?.name ?? "-" : "-"}
Noch keine Räume vorhanden.
Projektgeräte / Verbraucher {projectDeviceCount}
setProjectDeviceForm((current) => ({ ...current, name: event.target.value })) } />
setProjectDeviceForm((current) => ({ ...current, displayName: event.target.value })) } />
setProjectDeviceForm((current) => ({ ...current, category: event.target.value })) } />
setProjectDeviceForm((current) => ({ ...current, quantity: event.target.value })) } />
setProjectDeviceForm((current) => ({ ...current, installedPowerPerUnitKw: event.target.value, })) } />
setProjectDeviceForm((current) => ({ ...current, demandFactor: event.target.value })) } />
{projectDevices.map((device) => ( ))} {!projectDevices.length ? ( ) : null}
Interner Name Anzeigename Kategorie Anzahl Leistung je Stück [kW] GZF Aktionen
event.target.value !== device.name ? handleQuickUpdateProjectDevice(device, "name", event.target.value) : undefined } /> event.target.value !== device.displayName ? handleQuickUpdateProjectDevice(device, "displayName", event.target.value) : undefined } /> event.target.value !== (device.category ?? "") ? handleQuickUpdateProjectDevice(device, "category", event.target.value) : undefined } /> {device.quantity} {device.installedPowerPerUnitKw} {device.demandFactor}
Noch keine Projektgeräte vorhanden.
3 parallele Stromkreislisten öffnen
); }