"use client"; import Link from "next/link"; import { useParams } from "next/navigation"; import { FormEvent, useEffect, useMemo, useState } from "react"; import { copyGlobalDeviceToProject, copyDistributionBoard, copyProjectDeviceToGlobal, createDistributionBoard, createFloor, createProjectDevice, createRoom, deleteFloor, deleteProjectDevice, deleteRoom, deleteDistributionBoard, disconnectProjectDeviceRows, exportProjectTransfer, getProjectDeviceSyncPreview, listCircuitLists, listDistributionBoards, listFloors, listGlobalDevices, listProjectDevices, listProjects, listRooms, importProjectTransfer, synchronizeProjectDeviceRows, updateDistributionBoard, updateFloor, updateProjectDevice, updateProjectSettings, updateRoom, } from "../../../frontend/utils/api"; import type { CircuitListDto, CreateProjectDeviceInput, DistributionBoardDto, FloorDto, GlobalDeviceDto, ProjectDeviceDto, ProjectDeviceSyncPreviewDto, ProjectDto, RoomDto, } from "../../../frontend/types"; import { projectDeviceSyncFields, type ProjectDeviceSyncField, } from "../../../shared/constants/project-device-sync-fields"; import { distributionBoardSupplyTypeLabels, type DistributionBoardSupplyType, } from "../../../shared/constants/distribution-board"; import { ProjectVersionHistory } from "../../../frontend/components/project-version-history"; import { ProjectSettingsModal, type ProjectSettingsInput, } from "../../../frontend/components/project-settings-modal"; import { FormModal } from "../../../frontend/components/form-modal"; import { ProjectDeviceModal } from "../../../frontend/components/project-device-modal"; const projectDeviceSyncFieldLabels: Record = { name: "Technischer Name", displayName: "Anzeigename", phaseType: "Phasenart", connectionKind: "Anschlussart", costGroup: "Kostengruppe", category: "Kategorie", quantity: "Anzahl", powerPerUnit: "Leistung je Stück", simultaneityFactor: "Gleichzeitigkeitsfaktor", cosPhi: "cos Phi", remark: "Bemerkung", }; export default function ProjectDetailPage() { const params = useParams<{ projectId: string }>(); const [projectId, setProjectId] = useState(""); const [project, setProject] = useState(null); const [boards, setBoards] = useState([]); const [circuitLists, setCircuitLists] = useState([]); const [floors, setFloors] = useState([]); const [rooms, setRooms] = useState([]); const [projectDevices, setProjectDevices] = useState([]); const [globalDevices, setGlobalDevices] = useState([]); const [boardName, setBoardName] = useState(""); const [boardFloorId, setBoardFloorId] = useState(""); const [boardSupplyType, setBoardSupplyType] = useState("AV"); const [editingBoard, setEditingBoard] = useState(null); const [editingBoardFloorId, setEditingBoardFloorId] = useState(""); const [editingBoardSupplyType, setEditingBoardSupplyType] = useState("AV"); const [ editingBoardSimultaneityFactor, setEditingBoardSimultaneityFactor, ] = useState("1"); const [editingBoardCopyName, setEditingBoardCopyName] = useState(""); const [floorName, setFloorName] = useState(""); const [editingFloor, setEditingFloor] = useState(null); const [roomNumber, setRoomNumber] = useState(""); const [roomName, setRoomName] = useState(""); const [roomFloorId, setRoomFloorId] = useState(""); const [editingRoom, setEditingRoom] = useState(null); const [isProjectSettingsOpen, setIsProjectSettingsOpen] = useState(false); const [structureModal, setStructureModal] = useState< "board" | "floor" | "room" | null >(null); const [isProjectDeviceModalOpen, setIsProjectDeviceModalOpen] = useState(false); const [editingProjectDevice, setEditingProjectDevice] = useState(null); const [projectDeviceQuery, setProjectDeviceQuery] = useState(""); const [syncPreview, setSyncPreview] = useState(null); const [selectedSyncRowIds, setSelectedSyncRowIds] = useState([]); const [selectedSyncFields, setSelectedSyncFields] = 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), listCircuitLists(projectId), listFloors(projectId), listRooms(projectId), listProjectDevices(projectId), listGlobalDevices(), ]) .then(([ projects, distributionBoards, loadedCircuitLists, loadedFloors, loadedRooms, loadedProjectDevices, loadedGlobalDevices, ]) => { const currentProject = projects.find((item) => item.id === projectId) ?? null; setProject(currentProject); setBoards(distributionBoards); setCircuitLists(loadedCircuitLists); 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 visibleProjectDevices = useMemo(() => { const query = projectDeviceQuery.trim().toLocaleLowerCase("de"); if (!query) { return projectDevices; } return projectDevices.filter((device) => [ device.name, device.displayName, device.category, device.connectionKind, device.costGroup, ].some((value) => value?.toLocaleLowerCase("de").includes(query)) ); }, [projectDeviceQuery, projectDevices]); const floorById = useMemo(() => new Map(floors.map((item) => [item.id, item])), [floors]); const circuitListByBoardId = useMemo( () => new Map(circuitLists.map((circuitList) => [circuitList.distributionBoardId, circuitList])), [circuitLists] ); const enabledBoardSupplyTypes = project?.enabledDistributionBoardSupplyTypes ?? []; const usedBoardSupplyTypes = useMemo( () => [ ...new Set( boards .map((board) => board.supplyType) .filter( ( supplyType ): supplyType is DistributionBoardSupplyType => supplyType !== null ) ), ], [boards] ); function applyProjectRevision(currentRevision: number) { setProject((current) => current ? { ...current, currentRevision } : current ); } async function handleCreateBoard(event: FormEvent) { event.preventDefault(); if (!projectId || !project || !boardName.trim()) { return; } setIsSaving(true); setError(null); try { const result = await createDistributionBoard( projectId, { name: boardName.trim(), floorId: boardFloorId || null, supplyType: boardSupplyType, }, project.currentRevision ); setBoards((current) => [ ...current, result.distributionBoard, ]); setCircuitLists(await listCircuitLists(projectId)); applyProjectRevision(result.history.currentRevision); setBoardName(""); setBoardFloorId(""); setBoardSupplyType( project.enabledDistributionBoardSupplyTypes[0] ); setStructureModal(null); } catch (err) { setError(err instanceof Error ? err.message : "Verteilung konnte nicht erstellt werden."); } finally { setIsSaving(false); } } async function handleSaveFloor(event: FormEvent) { event.preventDefault(); if (!projectId || !project || !floorName.trim()) { return; } setIsSaving(true); setError(null); try { const result = editingFloor ? await updateFloor( projectId, editingFloor.id, { name: floorName.trim() }, project.currentRevision ) : await createFloor( projectId, { name: floorName.trim() }, project.currentRevision ); setFloors((current) => editingFloor ? current.map((floor) => floor.id === result.floor.id ? result.floor : floor ) : [...current, result.floor] ); applyProjectRevision(result.history.currentRevision); setFloorName(""); setEditingFloor(null); setStructureModal(null); } catch (err) { setError(err instanceof Error ? err.message : "Etage konnte nicht gespeichert werden."); } finally { setIsSaving(false); } } async function handleSaveRoom(event: FormEvent) { event.preventDefault(); if ( !projectId || !project || !roomNumber.trim() || !roomName.trim() ) { return; } setIsSaving(true); setError(null); try { const input = { floorId: roomFloorId || undefined, roomNumber: roomNumber.trim(), roomName: roomName.trim(), }; const result = editingRoom ? await updateRoom( projectId, editingRoom.id, input, project.currentRevision ) : await createRoom(projectId, input, project.currentRevision); setRooms((current) => editingRoom ? current.map((room) => room.id === result.room.id ? result.room : room ) : [...current, result.room] ); applyProjectRevision(result.history.currentRevision); setRoomNumber(""); setRoomName(""); setRoomFloorId(""); setEditingRoom(null); setStructureModal(null); } catch (err) { setError(err instanceof Error ? err.message : "Raum konnte nicht gespeichert werden."); } finally { setIsSaving(false); } } async function handleSaveProjectSettings(input: ProjectSettingsInput) { if (!projectId || !project) { return; } setIsSaving(true); setError(null); try { const result = await updateProjectSettings( projectId, project.currentRevision, input ); setProject(result.project); setIsProjectSettingsOpen(false); } catch (err) { setError(err instanceof Error ? err.message : "Projekteigenschaften konnten nicht gespeichert werden."); } finally { setIsSaving(false); } } async function handleCreateProjectDevice( payload: CreateProjectDeviceInput ) { if (!projectId || !project || !payload.name.trim()) { return; } setIsSaving(true); setError(null); try { const result = await createProjectDevice( projectId, payload, project.currentRevision ); setProjectDevices((current) => [...current, result.projectDevice]); applyProjectRevision(result.history.currentRevision); setIsProjectDeviceModalOpen(false); } catch (err) { setError(err instanceof Error ? err.message : "Projektgerät konnte nicht erstellt werden."); } finally { setIsSaving(false); } } async function handleDeleteProjectDevice(projectDeviceId: string) { if (!projectId || !project) { return; } setIsSaving(true); setError(null); try { const result = await deleteProjectDevice( projectId, projectDeviceId, project.currentRevision ); setProjectDevices((current) => current.filter((item) => item.id !== projectDeviceId)); applyProjectRevision(result.history.currentRevision); } catch (err) { setError(err instanceof Error ? err.message : "Projektgerät konnte nicht gelöscht werden."); } finally { setIsSaving(false); } } async function handleUpdateProjectDevice( device: ProjectDeviceDto, payload: CreateProjectDeviceInput ) { if (!projectId || !project) { return; } setIsSaving(true); setError(null); try { const result = await updateProjectDevice( projectId, device.id, payload, project.currentRevision ); setProjectDevices((current) => current.map((item) => item.id === device.id ? result.projectDevice : item ) ); applyProjectRevision(result.history.currentRevision); setEditingProjectDevice(null); await openProjectDeviceSyncPreview(result.projectDevice.id); } catch (err) { setError(err instanceof Error ? err.message : "Projektgerät konnte nicht aktualisiert werden."); } finally { setIsSaving(false); } } function openBoardEditor(board: DistributionBoardDto) { setEditingBoard(board); setEditingBoardFloorId(board.floorId ?? ""); setEditingBoardSupplyType( board.supplyType ?? project?.enabledDistributionBoardSupplyTypes[0] ?? "AV" ); setEditingBoardSimultaneityFactor( String(board.simultaneityFactor) ); setEditingBoardCopyName(`${board.name} Kopie`); } function openBoardCreator() { setBoardSupplyType( project?.enabledDistributionBoardSupplyTypes[0] ?? "AV" ); setStructureModal("board"); } async function handleUpdateBoard(event: FormEvent) { event.preventDefault(); if (!projectId || !project || !editingBoard) { return; } const simultaneityFactor = Number( editingBoardSimultaneityFactor ); if ( !editingBoardSimultaneityFactor.trim() || !Number.isFinite(simultaneityFactor) || simultaneityFactor < 0 || simultaneityFactor > 1 ) { return; } setIsSaving(true); setError(null); try { const result = await updateDistributionBoard( projectId, editingBoard.id, { floorId: editingBoardFloorId || null, supplyType: editingBoardSupplyType, simultaneityFactor, }, project.currentRevision ); setBoards((current) => current.map((board) => board.id === result.distributionBoard.id ? result.distributionBoard : board ) ); applyProjectRevision(result.history.currentRevision); setEditingBoard(null); } catch (err) { setError( err instanceof Error ? err.message : "Verteilung konnte nicht bearbeitet werden." ); } finally { setIsSaving(false); } } function openCreateFloor() { setEditingFloor(null); setFloorName(""); setStructureModal("floor"); } function openEditFloor(floor: FloorDto) { setEditingFloor(floor); setFloorName(floor.name); setStructureModal("floor"); } function openCreateRoom() { setEditingRoom(null); setRoomNumber(""); setRoomName(""); setRoomFloorId(""); setStructureModal("room"); } function openEditRoom(room: RoomDto) { setEditingRoom(room); setRoomNumber(room.roomNumber); setRoomName(room.roomName); setRoomFloorId(room.floorId ?? ""); setStructureModal("room"); } async function handleDeleteFloor() { if (!projectId || !project || !editingFloor) return; if (!window.confirm(`Etage „${editingFloor.name}“ wirklich löschen?`)) return; setIsSaving(true); setError(null); try { const result = await deleteFloor(projectId, editingFloor.id, project.currentRevision); setFloors((current) => current.filter((floor) => floor.id !== editingFloor.id)); applyProjectRevision(result.history.currentRevision); setEditingFloor(null); setFloorName(""); setStructureModal(null); } catch (err) { setError(err instanceof Error ? err.message : "Etage konnte nicht gelöscht werden."); } finally { setIsSaving(false); } } async function handleDeleteRoom() { if (!projectId || !project || !editingRoom) return; if (!window.confirm(`Raum „${editingRoom.roomNumber} ${editingRoom.roomName}“ wirklich löschen?`)) return; setIsSaving(true); setError(null); try { const result = await deleteRoom(projectId, editingRoom.id, project.currentRevision); setRooms((current) => current.filter((room) => room.id !== editingRoom.id)); applyProjectRevision(result.history.currentRevision); setEditingRoom(null); setRoomNumber(""); setRoomName(""); setRoomFloorId(""); setStructureModal(null); } catch (err) { setError(err instanceof Error ? err.message : "Raum konnte nicht gelöscht werden."); } finally { setIsSaving(false); } } async function handleCopyBoard() { if ( !projectId || !project || !editingBoard || !editingBoardCopyName.trim() ) { return; } setIsSaving(true); setError(null); try { const result = await copyDistributionBoard( projectId, editingBoard.id, editingBoardCopyName.trim(), project.currentRevision ); setBoards((current) => [ ...current, result.distributionBoard, ]); setCircuitLists((current) => [ ...current, result.circuitList, ]); applyProjectRevision(result.history.currentRevision); setEditingBoard(null); } catch (err) { setError( err instanceof Error ? err.message : "Verteilung konnte nicht kopiert werden." ); } finally { setIsSaving(false); } } async function handleDeleteBoard() { if (!projectId || !project || !editingBoard) { return; } const confirmed = window.confirm( `Verteilung „${editingBoard.name}“ wirklich löschen?\n\n` + "Dabei werden die Stromkreisliste, alle Gruppen, Stromkreise, Gerätezeilen, Schutzgeräte und weiteren Verteilergeräte entfernt. " + "Der Vorgang kann anschließend über die projektweite Historie rückgängig gemacht werden." ); if (!confirmed) { return; } setIsSaving(true); setError(null); try { const result = await deleteDistributionBoard( projectId, editingBoard.id, project.currentRevision ); setBoards((current) => current.filter((board) => board.id !== result.distributionBoardId) ); setCircuitLists((current) => current.filter( (circuitList) => circuitList.distributionBoardId !== result.distributionBoardId ) ); applyProjectRevision(result.history.currentRevision); setEditingBoard(null); } catch (err) { setError( err instanceof Error ? err.message : "Verteilung konnte nicht gelöscht werden." ); } finally { setIsSaving(false); } } async function handleExportProject() { if (!project) { return; } setIsSaving(true); setError(null); try { const transfer = await exportProjectTransfer(project.id); const blob = new Blob([JSON.stringify(transfer, null, 2)], { type: "application/json", }); const url = URL.createObjectURL(blob); const anchor = document.createElement("a"); anchor.href = url; anchor.download = `${project.name.replace(/[^a-zA-Z0-9_-]+/g, "-") || "projekt"}.leistungsbilanz.json`; anchor.click(); URL.revokeObjectURL(url); } catch (err) { setError( err instanceof Error ? err.message : "Projekt konnte nicht exportiert werden." ); } finally { setIsSaving(false); } } async function handleImportProject( transfer: unknown, mode: "replace" | "duplicate" ) { if (!project) { return; } setIsSaving(true); setError(null); try { const result = await importProjectTransfer( project.id, mode, project.currentRevision, transfer ); if (mode === "duplicate" && "projectId" in result) { window.location.href = `/projects/${result.projectId}`; return; } window.location.reload(); } catch (err) { setError( err instanceof Error ? err.message : "Projektdatei konnte nicht importiert werden." ); setIsProjectSettingsOpen(false); } finally { setIsSaving(false); } } async function openProjectDeviceSyncPreview(projectDeviceId: string) { if (!projectId) { return; } try { const preview = await getProjectDeviceSyncPreview(projectId, projectDeviceId); setSyncPreview(preview); setSelectedSyncRowIds(preview.rows.filter((row) => row.differences.length > 0).map((row) => row.rowId)); const differentFields = new Set( preview.rows.flatMap((row) => row.differences.map((difference) => difference.field)) ); setSelectedSyncFields( projectDeviceSyncFields.filter((field) => field !== "displayName" && differentFields.has(field)) ); } catch (err) { setError(err instanceof Error ? err.message : "Verknüpfungen konnten nicht geladen werden."); } } function toggleSyncRow(rowId: string) { setSelectedSyncRowIds((current) => current.includes(rowId) ? current.filter((id) => id !== rowId) : [...current, rowId] ); } function toggleSyncField(field: ProjectDeviceSyncField) { setSelectedSyncFields((current) => current.includes(field) ? current.filter((entry) => entry !== field) : [...current, field] ); } async function handleSynchronizeProjectDeviceRows() { if ( !projectId || !project || !syncPreview || selectedSyncRowIds.length === 0 || selectedSyncFields.length === 0 ) { return; } setIsSaving(true); setError(null); try { const result = await synchronizeProjectDeviceRows( projectId, syncPreview.projectDevice.id, selectedSyncRowIds, selectedSyncFields, project.currentRevision ); setSyncPreview(result.preview); applyProjectRevision(result.history.currentRevision); setSelectedSyncRowIds( result.preview.rows.filter((row) => row.differences.length > 0).map((row) => row.rowId) ); } catch (err) { setError(err instanceof Error ? err.message : "Gerätezeilen konnten nicht synchronisiert werden."); } finally { setIsSaving(false); } } async function handleDisconnectProjectDeviceRows() { if ( !projectId || !project || !syncPreview || selectedSyncRowIds.length === 0 ) { return; } setIsSaving(true); setError(null); try { const result = await disconnectProjectDeviceRows( projectId, syncPreview.projectDevice.id, selectedSyncRowIds, project.currentRevision ); setSyncPreview(result.preview); setSelectedSyncRowIds( result.preview.rows .filter((row) => row.differences.length > 0) .map((row) => row.rowId) ); applyProjectRevision(result.history.currentRevision); } catch (err) { setError(err instanceof Error ? err.message : "Verknüpfungen konnten nicht getrennt werden."); } finally { setIsSaving(false); } } async function handleCopyGlobalToProject(globalDeviceId: string) { if (!projectId || !project || !globalDeviceId) { return; } setIsSaving(true); setError(null); try { const result = await copyGlobalDeviceToProject( projectId, globalDeviceId, project.currentRevision ); setProjectDevices((current) => [...current, result.projectDevice]); applyProjectRevision(result.history.currentRevision); setIsProjectDeviceModalOpen(false); } 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 (
Projekt

{project?.name ?? "Projekt"}

{project?.internalProjectNumber ? `Projektnummer ${project.internalProjectNumber} · ` : ""} Verteilerübersicht und Einstieg in die Stromkreislisten

Zur Projektübersicht
{error ?
{error}
: null}
{project ? (
window.location.reload()} projectId={projectId} />
) : null}
Verteilungen {boardCount}
{boards.map((board) => { const circuitList = circuitListByBoardId.get(board.id); return ( ); })} {!boards.length ? ( ) : null}
Verteilung Etage Netzart GZF Aktionen
{board.name} {board.floorId ? floorById.get(board.floorId)?.name ?? "Unbekannt" : "Ohne Etage"} {board.supplyType ? distributionBoardSupplyTypeLabels[ board.supplyType ] : "Nicht festgelegt"} {board.simultaneityFactor.toLocaleString( "de-DE", { minimumFractionDigits: 2, maximumFractionDigits: 2, } )}
{circuitList ? ( Stromkreisliste öffnen ) : ( Keine Stromkreisliste vorhanden )}
Noch keine Verteilungen vorhanden.
Etagen {floorCount}
    {floors.map((floor) => (
  • {floor.name}
  • ))} {!floors.length ? (
  • Noch keine Etagen vorhanden.
  • ) : null}
Räume {roomCount}
{rooms.map((room) => ( ))} {!rooms.length ? ( ) : null}
Raumnummer Raumname Etage Aktionen
{room.roomNumber} {room.roomName} {room.floorId ? floorById.get(room.floorId)?.name ?? "-" : "-"}
Noch keine Räume vorhanden.
Projektgeräte {projectDeviceCount}
setProjectDeviceQuery(event.target.value)} placeholder="Geräte durchsuchen" type="search" value={projectDeviceQuery} />
{visibleProjectDevices.map((device) => ( ))} {!visibleProjectDevices.length ? ( ) : null}
Gerät Anschluss Leistung Kostengruppe Aktionen
{device.displayName}
{device.name} {device.category ? ` · ${device.category}` : ""}
{device.phaseType === "three_phase" ? "3-phasig" : "1-phasig"} {device.connectionKind ? (
{device.connectionKind}
) : null}
{device.totalPower} kW
{device.quantity} × {device.powerPerUnit} kW · GZF{" "} {device.simultaneityFactor}
{device.costGroup ?? "-"}
{projectDevices.length ? "Keine Projektgeräte entsprechen der Suche." : "Noch keine Projektgeräte vorhanden."}
{syncPreview ? (

Verknüpfte Zeilen: {syncPreview.projectDevice.displayName}

Nur ausgewählte Felder und Zeilen werden übernommen. Der Anzeigename bleibt standardmäßig lokal.

{projectDeviceSyncFields.map((field) => ( ))}
{syncPreview.rows.map((row) => ( ))} {syncPreview.rows.length === 0 ? ( ) : null}
Auswahl Verteilung / Stromkreis Gerätezeile Abweichungen
toggleSyncRow(row.rowId)} /> {row.distributionBoardName}
{row.equipmentIdentifier} {row.circuitDisplayName ? ` – ${row.circuitDisplayName}` : ""}
{row.rowDisplayName}
{row.differences.map((difference) => ( {projectDeviceSyncFieldLabels[difference.field]}: {String(difference.currentValue ?? "–")} →{" "} {String(difference.sourceValue ?? "–")} ))} {row.differences.length === 0 ? ( Aktuell ) : null}
Keine verknüpften Gerätezeilen im neuen Stromkreismodell vorhanden.
) : null}
{structureModal === "board" ? ( setStructureModal(null)} onSubmit={handleCreateBoard} submitDisabled={!boardName.trim()} submitLabel="Verteilung erstellen" title="Verteilung hinzufügen" > setBoardName(event.target.value)} placeholder="z. B. UV-01" required value={boardName} />
) : null} {editingBoard ? ( setEditingBoard(null)} onSubmit={handleUpdateBoard} submitDisabled={ !editingBoardSimultaneityFactor.trim() || !Number.isFinite( Number(editingBoardSimultaneityFactor) ) || Number(editingBoardSimultaneityFactor) < 0 || Number(editingBoardSimultaneityFactor) > 1 } submitLabel="Änderungen speichern" title="Verteilung bearbeiten" >
setEditingBoardSimultaneityFactor( event.target.value ) } required step="0.01" type="number" value={editingBoardSimultaneityFactor} />
Wird auf die Gesamtleistung des Verteilers angewendet.

Verteilung kopieren

Erstellt eine vollständige Kopie des zuletzt gespeicherten Stands einschließlich Gruppen, Stromkreisen, Gerätezeilen und Schutzgeräten. Noch nicht gespeicherte Änderungen oben werden nicht übernommen.

setEditingBoardCopyName(event.target.value) } value={editingBoardCopyName} />

Gefahrenbereich

Entfernt die vollständige Verteilung. Die Aktion wird erst nach einer ausdrücklichen Warnung ausgeführt und kann über die projektweite Historie rückgängig gemacht werden.

) : null} {structureModal === "floor" ? ( { setStructureModal(null); setEditingFloor(null); }} onSubmit={handleSaveFloor} submitDisabled={!floorName.trim()} submitLabel={editingFloor ? "Änderungen speichern" : "Etage hinzufügen"} title={editingFloor ? "Etage bearbeiten" : "Etage hinzufügen"} > setFloorName(event.target.value)} placeholder="z. B. EG" required value={floorName} /> {editingFloor ? (

Etagen mit zugeordneten Räumen oder Verteilungen können nicht gelöscht werden.

) : null}
) : null} {structureModal === "room" ? ( { setStructureModal(null); setEditingRoom(null); }} onSubmit={handleSaveRoom} submitDisabled={!roomNumber.trim() || !roomName.trim()} submitLabel={editingRoom ? "Änderungen speichern" : "Raum anlegen"} title={editingRoom ? "Raum bearbeiten" : "Raum hinzufügen"} >
setRoomNumber(event.target.value)} required value={roomNumber} />
setRoomName(event.target.value)} required value={roomName} />
{editingRoom ? (

In Stromkreisen verwendete Räume können nicht gelöscht werden.

) : null}
) : null} {isProjectDeviceModalOpen ? ( setIsProjectDeviceModalOpen(false)} onImportGlobal={handleCopyGlobalToProject} onSave={handleCreateProjectDevice} /> ) : null} {editingProjectDevice ? ( setEditingProjectDevice(null)} onImportGlobal={handleCopyGlobalToProject} onSave={(input) => handleUpdateProjectDevice(editingProjectDevice, input) } /> ) : null} {project && isProjectSettingsOpen ? ( setIsProjectSettingsOpen(false)} onExport={handleExportProject} onImport={handleImportProject} onSave={handleSaveProjectSettings} project={project} usedDistributionBoardSupplyTypes={usedBoardSupplyTypes} /> ) : null}
); }