"use client"; import Link from "next/link"; import { useParams, useSearchParams } from "next/navigation"; import { FormEvent, useEffect, useMemo, useState } from "react"; import { createConsumer, deleteConsumer, getProject, listConsumers, listDistributionBoards, listProjectDevices, listRooms, updateConsumer, } from "../../../../frontend/utils/api"; import type { ConsumerWithCalculatedValues, CreateConsumerInput, DistributionBoardDto, ProjectDeviceDto, ProjectDto, RoomDto, } from "../../../../frontend/types"; import { cableCrossSectionOptions, cableTypeOptions, consumerGroupOptions, deviceTypeOptions, phaseTypeOptions, protectionCharacteristicOptions, protectionTypeOptions, tradeOrCostGroupOptions, } from "../../../../shared/constants/consumer-option-lists"; interface SlotState { boardId: string; selectedConsumerIds: string[]; } interface QuickCreateFormState { name: string; roomId: string; quantity: string; installedPowerPerUnitKw: string; demandFactor: string; totalPowerKw: string; addCount: string; } type SortField = "name" | "circuitNumber" | "quantity" | "installedPowerPerUnitKw" | "demandFactor" | "demandPowerKw"; type SortDirection = "asc" | "desc"; interface ListFilterState { query: string; sortField: SortField; sortDirection: SortDirection; } interface BulkEditState { quantity: string; installedPowerPerUnitKw: string; demandFactor: string; } type ColumnKey = | "selection" | "circuitNumber" | "description" | "name" | "projectDevice" | "deviceLink" | "room" | "floor" | "category" | "deviceType" | "phaseType" | "tradeOrCostGroup" | "group" | "protectionType" | "protectionRatedCurrent" | "protectionCharacteristic" | "cableType" | "cableCrossSection" | "comment" | "quantity" | "installedPowerPerUnitKw" | "installedPowerKw" | "demandFactor" | "demandPowerKw" | "voltageV" | "phaseCount" | "powerFactor" | "currentA" | "note" | "actions"; const defaultSlots: SlotState[] = [ { boardId: "", selectedConsumerIds: [] }, { boardId: "", selectedConsumerIds: [] }, { boardId: "", selectedConsumerIds: [] }, ]; const defaultCreateForm: QuickCreateFormState = { name: "", roomId: "", quantity: "1", installedPowerPerUnitKw: "0.10", demandFactor: "1.00", totalPowerKw: "0.10", addCount: "1", }; const defaultFilterState: ListFilterState = { query: "", sortField: "name", sortDirection: "asc", }; const defaultBulkEditState: BulkEditState = { quantity: "", installedPowerPerUnitKw: "", demandFactor: "", }; const allColumns: Array<{ key: ColumnKey; label: string }> = [ { key: "selection", label: "Auswahl" }, { key: "circuitNumber", label: "Stromkreis-Nr." }, { key: "description", label: "Beschreibung" }, { key: "name", label: "Verbraucher" }, { key: "projectDevice", label: "Projektgerät" }, { key: "deviceLink", label: "Verknüpfung" }, { key: "room", label: "Raum" }, { key: "floor", label: "Etage" }, { key: "category", label: "Kategorie" }, { key: "deviceType", label: "Geräteart" }, { key: "phaseType", label: "Phasenart" }, { key: "tradeOrCostGroup", label: "Kostengruppe" }, { key: "group", label: "Gruppe" }, { key: "protectionType", label: "Schutzart" }, { key: "protectionRatedCurrent", label: "Schutznennstrom [A]" }, { key: "protectionCharacteristic", label: "Schutzkennlinie" }, { key: "cableType", label: "Kabeltyp" }, { key: "cableCrossSection", label: "Querschnitt" }, { key: "comment", label: "Kommentar" }, { key: "quantity", label: "Anzahl" }, { key: "installedPowerPerUnitKw", label: "Einzelleistung [kW]" }, { key: "installedPowerKw", label: "Installierte Leistung [kW]" }, { key: "demandFactor", label: "Gleichzeitigkeitsfaktor" }, { key: "demandPowerKw", label: "Gesamtleistung [kW]" }, { key: "voltageV", label: "Spannung [V]" }, { key: "phaseCount", label: "Phasen" }, { key: "powerFactor", label: "cos f" }, { key: "currentA", label: "Strom [A]" }, { key: "note", label: "Bemerkung" }, { key: "actions", label: "Aktionen" }, ]; const defaultVisibleColumns: ColumnKey[] = [ "selection", "circuitNumber", "description", "name", "projectDevice", "deviceLink", "room", "quantity", "installedPowerPerUnitKw", "demandFactor", "demandPowerKw", "actions", ]; function formatNumber(value: number | undefined, digits = 2) { if (value === undefined || Number.isNaN(value)) { return "-"; } return value.toFixed(digits); } function roomLabel(room: RoomDto) { return `${room.roomNumber} - ${room.roomName}`; } export default function CircuitListsPage() { const params = useParams<{ projectId: string }>(); const searchParams = useSearchParams(); const [projectId, setProjectId] = useState(""); const [project, setProject] = useState(null); const [boards, setBoards] = useState([]); const [rooms, setRooms] = useState([]); const [projectDevices, setProjectDevices] = useState([]); const [consumers, setConsumers] = useState([]); const [slots, setSlots] = useState(defaultSlots); const [activeListCount, setActiveListCount] = useState(1); const [newDeviceTemplateId, setNewDeviceTemplateId] = useState>({ 0: "", 1: "", 2: "", }); const [quickCreateForms, setQuickCreateForms] = useState>({ 0: { ...defaultCreateForm }, 1: { ...defaultCreateForm }, 2: { ...defaultCreateForm }, }); const [visibleColumns, setVisibleColumns] = useState(defaultVisibleColumns); const [listFilters, setListFilters] = useState>({ 0: { ...defaultFilterState }, 1: { ...defaultFilterState }, 2: { ...defaultFilterState }, }); const [bulkEditForms, setBulkEditForms] = useState>({ 0: { ...defaultBulkEditState }, 1: { ...defaultBulkEditState }, 2: { ...defaultBulkEditState }, }); const [showColumnManager, setShowColumnManager] = useState(false); const [error, setError] = useState(null); const [isSaving, setIsSaving] = useState(false); useEffect(() => { setProjectId(params.projectId); }, [params.projectId]); useEffect(() => { if (!projectId) { return; } Promise.all([ getProject(projectId), listDistributionBoards(projectId), listRooms(projectId), listProjectDevices(projectId), listConsumers(projectId), ]) .then(([loadedProject, distributionBoards, loadedRooms, loadedProjectDevices, loadedConsumers]) => { const initialBoardId = searchParams.get("boardId") ?? distributionBoards[0]?.id ?? ""; setProject(loadedProject); setBoards(distributionBoards); setRooms(loadedRooms); setProjectDevices(loadedProjectDevices); setConsumers(loadedConsumers); setSlots((current) => [ { ...current[0], boardId: current[0].boardId || initialBoardId }, current[1], current[2], ]); setActiveListCount(1); setError(null); }) .catch((err: unknown) => setError(err instanceof Error ? err.message : "Stromkreislisten konnten nicht geladen werden.") ); }, [projectId, searchParams]); const boardById = useMemo(() => new Map(boards.map((board) => [board.id, board])), [boards]); const slotColumnClass = activeListCount === 1 ? "col-12" : activeListCount === 2 ? "col-12 col-xxl-6" : "col-12 col-xxl-4"; function consumersForBoard(boardId: string) { return consumers.filter((item) => item.distributionBoardId === boardId); } function updateListFilter(slotIndex: number, patch: Partial) { setListFilters((current) => ({ ...current, [slotIndex]: { ...current[slotIndex], ...patch }, })); } function updateBulkEditForm(slotIndex: number, patch: Partial) { setBulkEditForms((current) => ({ ...current, [slotIndex]: { ...current[slotIndex], ...patch }, })); } function getComparableSortValue(consumer: ConsumerWithCalculatedValues, sortField: SortField): number | string { switch (sortField) { case "name": return (consumer.name ?? "").toLocaleLowerCase("de-DE"); case "circuitNumber": return (consumer.circuitNumber ?? "").toLocaleLowerCase("de-DE"); case "quantity": return consumer.quantity ?? 0; case "installedPowerPerUnitKw": return consumer.installedPowerPerUnitKw ?? 0; case "demandFactor": return consumer.demandFactor ?? 0; case "demandPowerKw": return consumer.demandPowerKw ?? 0; default: return ""; } } function setSlotBoard(slotIndex: number, boardId: string) { setSlots((current) => current.map((slot, index) => (index === slotIndex ? { boardId, selectedConsumerIds: [] } : slot)) ); } function addList() { setActiveListCount((current) => Math.min(3, current + 1)); } function removeList() { setActiveListCount((current) => { const next = Math.max(1, current - 1); setSlots((slotState) => slotState.map((slot, index) => (index >= next ? { boardId: "", selectedConsumerIds: [] } : slot)) ); return next; }); } function toggleConsumerSelection(slotIndex: number, consumerId: string) { setSlots((current) => current.map((slot, index) => { if (index !== slotIndex) { return slot; } const exists = slot.selectedConsumerIds.includes(consumerId); return { ...slot, selectedConsumerIds: exists ? slot.selectedConsumerIds.filter((id) => id !== consumerId) : [...slot.selectedConsumerIds, consumerId], }; }) ); } function updateQuickCreateForm(slotIndex: number, patch: Partial) { setQuickCreateForms((current) => { const next = { ...current[slotIndex], ...patch }; const quantity = Number(next.quantity); const unit = Number(next.installedPowerPerUnitKw); const demandFactor = Number(next.demandFactor); if (!Number.isNaN(quantity) && !Number.isNaN(unit) && !Number.isNaN(demandFactor)) { next.totalPowerKw = String(quantity * unit * demandFactor); } return { ...current, [slotIndex]: next }; }); } function updateTotalPower(slotIndex: number, totalPowerKw: string) { setQuickCreateForms((current) => { const next = { ...current[slotIndex], totalPowerKw }; const quantity = Number(next.quantity); const demandFactor = Number(next.demandFactor); const total = Number(totalPowerKw); if ( !Number.isNaN(quantity) && !Number.isNaN(demandFactor) && !Number.isNaN(total) && quantity > 0 && demandFactor > 0 ) { next.installedPowerPerUnitKw = String(total / (quantity * demandFactor)); } return { ...current, [slotIndex]: next }; }); } async function reloadConsumers() { if (!projectId) { return; } setConsumers(await listConsumers(projectId)); } async function handleCreateManualConsumer(slotIndex: number, event: FormEvent) { event.preventDefault(); const slot = slots[slotIndex]; const form = quickCreateForms[slotIndex]; const name = form.name.trim(); if (!projectId || !slot.boardId || !name) { return; } const payload: CreateConsumerInput = { projectId, distributionBoardId: slot.boardId, isLinkedToDevice: false, roomId: form.roomId || undefined, description: name, name, quantity: Number(form.quantity), installedPowerPerUnitKw: Number(form.installedPowerPerUnitKw), demandFactor: Number(form.demandFactor), phaseCount: 1, powerFactor: 1, }; setIsSaving(true); setError(null); try { await createConsumer(payload); setQuickCreateForms((current) => ({ ...current, [slotIndex]: { ...defaultCreateForm, roomId: current[slotIndex].roomId }, })); await reloadConsumers(); } catch (err) { setError(err instanceof Error ? err.message : "Verbraucher konnte nicht erstellt werden."); } finally { setIsSaving(false); } } async function handleCreateFromProjectDevice(slotIndex: number) { const slot = slots[slotIndex]; const form = quickCreateForms[slotIndex]; const templateId = newDeviceTemplateId[slotIndex]; const projectDevice = projectDevices.find((item) => item.id === templateId); if (!projectId || !slot.boardId || !projectDevice) { return; } const addCountRaw = Number(form.addCount); const addCount = Number.isFinite(addCountRaw) ? Math.max(1, Math.floor(addCountRaw)) : 1; const payload: CreateConsumerInput = { projectId, distributionBoardId: slot.boardId, projectDeviceId: projectDevice.id, isLinkedToDevice: true, roomId: form.roomId || undefined, description: projectDevice.displayName, name: projectDevice.displayName, category: projectDevice.category ?? undefined, quantity: projectDevice.quantity, installedPowerPerUnitKw: projectDevice.installedPowerPerUnitKw, demandFactor: projectDevice.demandFactor, phaseCount: projectDevice.phaseCount ?? 1, powerFactor: projectDevice.powerFactor ?? 1, note: projectDevice.note ?? undefined, }; setIsSaving(true); setError(null); try { await Promise.all(Array.from({ length: addCount }, () => createConsumer(payload))); await reloadConsumers(); } catch (err) { setError(err instanceof Error ? err.message : "Verbraucher konnte nicht aus Projektgerät erstellt werden."); } finally { setIsSaving(false); } } async function handleCopyToSlot(sourceConsumer: ConsumerWithCalculatedValues, targetSlotIndex: number) { const targetBoardId = slots[targetSlotIndex].boardId; if (!projectId || !targetBoardId) { return; } const payload: CreateConsumerInput = { projectId, distributionBoardId: targetBoardId, projectDeviceId: sourceConsumer.projectDeviceId ?? undefined, isLinkedToDevice: sourceConsumer.isLinkedToDevice, circuitNumber: sourceConsumer.circuitNumber, description: sourceConsumer.description, roomId: sourceConsumer.roomId ?? undefined, name: sourceConsumer.name, category: sourceConsumer.category, deviceType: sourceConsumer.deviceType, phaseType: sourceConsumer.phaseType, tradeOrCostGroup: sourceConsumer.tradeOrCostGroup, group: sourceConsumer.group, protectionType: sourceConsumer.protectionType, protectionRatedCurrent: sourceConsumer.protectionRatedCurrent, protectionCharacteristic: sourceConsumer.protectionCharacteristic, cableType: sourceConsumer.cableType, cableCrossSection: sourceConsumer.cableCrossSection, comment: sourceConsumer.comment, quantity: sourceConsumer.quantity, installedPowerPerUnitKw: sourceConsumer.installedPowerPerUnitKw, demandFactor: sourceConsumer.demandFactor, voltageV: sourceConsumer.voltageV, phaseCount: sourceConsumer.phaseCount, powerFactor: sourceConsumer.powerFactor, note: sourceConsumer.note, }; setIsSaving(true); setError(null); try { await createConsumer(payload); await reloadConsumers(); } catch (err) { setError(err instanceof Error ? err.message : "Kopieren in Ziel-Stromkreisliste fehlgeschlagen."); } finally { setIsSaving(false); } } async function handleDuplicateInSameList(sourceConsumer: ConsumerWithCalculatedValues) { if (!projectId || !sourceConsumer.distributionBoardId) { return; } const payload: CreateConsumerInput = { projectId, distributionBoardId: sourceConsumer.distributionBoardId, projectDeviceId: sourceConsumer.projectDeviceId ?? undefined, isLinkedToDevice: sourceConsumer.isLinkedToDevice, circuitNumber: sourceConsumer.circuitNumber, description: sourceConsumer.description, roomId: sourceConsumer.roomId ?? undefined, name: sourceConsumer.name, category: sourceConsumer.category, deviceType: sourceConsumer.deviceType, phaseType: sourceConsumer.phaseType, tradeOrCostGroup: sourceConsumer.tradeOrCostGroup, group: sourceConsumer.group, protectionType: sourceConsumer.protectionType, protectionRatedCurrent: sourceConsumer.protectionRatedCurrent, protectionCharacteristic: sourceConsumer.protectionCharacteristic, cableType: sourceConsumer.cableType, cableCrossSection: sourceConsumer.cableCrossSection, comment: sourceConsumer.comment, quantity: sourceConsumer.quantity, installedPowerPerUnitKw: sourceConsumer.installedPowerPerUnitKw, demandFactor: sourceConsumer.demandFactor, voltageV: sourceConsumer.voltageV, phaseCount: sourceConsumer.phaseCount, powerFactor: sourceConsumer.powerFactor, note: sourceConsumer.note, }; setIsSaving(true); setError(null); try { await createConsumer(payload); await reloadConsumers(); } catch (err) { setError(err instanceof Error ? err.message : "Duplizieren in derselben Liste fehlgeschlagen."); } finally { setIsSaving(false); } } async function handleCopySelectionToSlot(sourceSlotIndex: number, targetSlotIndex: number) { const sourceSlot = slots[sourceSlotIndex]; const targetBoardId = slots[targetSlotIndex].boardId; if (!projectId || !targetBoardId || !sourceSlot.selectedConsumerIds.length) { return; } const selected = consumers.filter((consumer) => sourceSlot.selectedConsumerIds.includes(consumer.id)); if (!selected.length) { return; } setIsSaving(true); setError(null); try { await Promise.all( selected.map((sourceConsumer) => createConsumer({ projectId, distributionBoardId: targetBoardId, projectDeviceId: sourceConsumer.projectDeviceId ?? undefined, isLinkedToDevice: sourceConsumer.isLinkedToDevice, circuitNumber: sourceConsumer.circuitNumber, description: sourceConsumer.description, roomId: sourceConsumer.roomId ?? undefined, name: sourceConsumer.name, category: sourceConsumer.category, deviceType: sourceConsumer.deviceType, phaseType: sourceConsumer.phaseType, tradeOrCostGroup: sourceConsumer.tradeOrCostGroup, group: sourceConsumer.group, protectionType: sourceConsumer.protectionType, protectionRatedCurrent: sourceConsumer.protectionRatedCurrent, protectionCharacteristic: sourceConsumer.protectionCharacteristic, cableType: sourceConsumer.cableType, cableCrossSection: sourceConsumer.cableCrossSection, comment: sourceConsumer.comment, quantity: sourceConsumer.quantity, installedPowerPerUnitKw: sourceConsumer.installedPowerPerUnitKw, demandFactor: sourceConsumer.demandFactor, voltageV: sourceConsumer.voltageV, phaseCount: sourceConsumer.phaseCount, powerFactor: sourceConsumer.powerFactor, note: sourceConsumer.note, }) ) ); await reloadConsumers(); setSlots((current) => current.map((slot, index) => (index === sourceSlotIndex ? { ...slot, selectedConsumerIds: [] } : slot)) ); } catch (err) { setError(err instanceof Error ? err.message : "Sammel-Kopieren fehlgeschlagen."); } finally { setIsSaving(false); } } async function handleBulkEditSelection(slotIndex: number) { const slot = slots[slotIndex]; if (!slot.selectedConsumerIds.length) { return; } const form = bulkEditForms[slotIndex]; const patch: Partial = {}; const quantity = form.quantity.trim(); const installedPowerPerUnitKw = form.installedPowerPerUnitKw.trim(); const demandFactor = form.demandFactor.trim(); if (quantity) { const value = Number(quantity); if (!Number.isNaN(value) && value >= 0) { patch.quantity = value; } } if (installedPowerPerUnitKw) { const value = Number(installedPowerPerUnitKw); if (!Number.isNaN(value) && value >= 0) { patch.installedPowerPerUnitKw = value; } } if (demandFactor) { const value = Number(demandFactor); if (!Number.isNaN(value) && value >= 0 && value <= 1) { patch.demandFactor = value; } } if (!Object.keys(patch).length) { return; } const selected = consumers.filter((consumer) => slot.selectedConsumerIds.includes(consumer.id)); if (!selected.length) { return; } setIsSaving(true); setError(null); try { await Promise.all(selected.map((consumer) => handleInlineUpdateFields(consumer, patch))); await reloadConsumers(); setBulkEditForms((current) => ({ ...current, [slotIndex]: { ...defaultBulkEditState } })); } catch (err) { setError(err instanceof Error ? err.message : "Sammeländerung fehlgeschlagen."); } finally { setIsSaving(false); } } async function handleInlineUpdateFields( consumer: ConsumerWithCalculatedValues, patch: Partial ) { const payload = { projectId, distributionBoardId: patch.distributionBoardId !== undefined ? patch.distributionBoardId : consumer.distributionBoardId ?? undefined, circuitListId: patch.circuitListId !== undefined ? patch.circuitListId : consumer.circuitListId ?? undefined, projectDeviceId: patch.projectDeviceId !== undefined ? patch.projectDeviceId : consumer.projectDeviceId ?? undefined, isLinkedToDevice: patch.isLinkedToDevice !== undefined ? patch.isLinkedToDevice : consumer.isLinkedToDevice ?? false, circuitNumber: patch.circuitNumber !== undefined ? patch.circuitNumber : consumer.circuitNumber, description: patch.description !== undefined ? patch.description : consumer.description, roomId: patch.roomId !== undefined ? patch.roomId : consumer.roomId ?? undefined, name: patch.name ?? consumer.name, category: patch.category !== undefined ? patch.category : consumer.category ?? undefined, deviceType: patch.deviceType !== undefined ? patch.deviceType : consumer.deviceType, phaseType: patch.phaseType !== undefined ? patch.phaseType : consumer.phaseType, tradeOrCostGroup: patch.tradeOrCostGroup !== undefined ? patch.tradeOrCostGroup : consumer.tradeOrCostGroup, group: patch.group !== undefined ? patch.group : consumer.group, protectionType: patch.protectionType !== undefined ? patch.protectionType : consumer.protectionType, protectionRatedCurrent: patch.protectionRatedCurrent !== undefined ? patch.protectionRatedCurrent : consumer.protectionRatedCurrent, protectionCharacteristic: patch.protectionCharacteristic !== undefined ? patch.protectionCharacteristic : consumer.protectionCharacteristic, cableType: patch.cableType !== undefined ? patch.cableType : consumer.cableType, cableCrossSection: patch.cableCrossSection !== undefined ? patch.cableCrossSection : consumer.cableCrossSection, comment: patch.comment !== undefined ? patch.comment : consumer.comment, quantity: patch.quantity ?? consumer.quantity, installedPowerPerUnitKw: patch.installedPowerPerUnitKw ?? consumer.installedPowerPerUnitKw, demandFactor: patch.demandFactor ?? consumer.demandFactor, voltageV: patch.voltageV !== undefined ? patch.voltageV : consumer.voltageV, phaseCount: patch.phaseCount !== undefined ? patch.phaseCount : consumer.phaseCount, powerFactor: patch.powerFactor !== undefined ? patch.powerFactor : consumer.powerFactor, note: patch.note !== undefined ? patch.note : consumer.note, }; try { const updated = await updateConsumer(consumer.id, payload); setConsumers((current) => current.map((item) => (item.id === consumer.id ? updated : item))); } catch (err) { setError(err instanceof Error ? err.message : "Aktualisierung fehlgeschlagen."); } } async function handleDeleteConsumer(consumerId: string) { setIsSaving(true); setError(null); try { await deleteConsumer(consumerId); await reloadConsumers(); } catch (err) { setError(err instanceof Error ? err.message : "Verbraucher konnte nicht gelöscht werden."); } finally { setIsSaving(false); } } function toggleColumn(column: ColumnKey) { if (column === "selection" || column === "actions") { return; } setVisibleColumns((current) => current.includes(column) ? current.filter((item) => item !== column) : [...current, column] ); } function moveColumn(column: ColumnKey, direction: -1 | 1) { setVisibleColumns((current) => { const index = current.indexOf(column); if (index < 0) { return current; } const nextIndex = index + direction; if (nextIndex < 0 || nextIndex >= current.length) { return current; } const clone = [...current]; const [item] = clone.splice(index, 1); clone.splice(nextIndex, 0, item); return clone; }); } const renderedColumns = allColumns.filter((column) => visibleColumns.includes(column.key)); return (

Stromkreislisten

Projekt: {project?.name ?? projectId}

Zurück zu Verteilern

Aktiv geöffnet: {activeListCount} von maximal 3 Listen.

{error ?
{error}
: null} {showColumnManager ? (
Spaltenauswahl und Reihenfolge
{allColumns .filter((column) => column.key !== "selection" && column.key !== "actions") .map((column) => (
))}
Standardmäßig sind cos f, Phasen und Strom ausgeblendet. Du kannst sie hier jederzeit einblenden.
) : null}
{slots.slice(0, activeListCount).map((slot, slotIndex) => { const currentFilter = listFilters[slotIndex]; const bulkEditForm = bulkEditForms[slotIndex]; const baseConsumersForSlot = slot.boardId ? consumersForBoard(slot.boardId) : []; const query = currentFilter.query.trim().toLocaleLowerCase("de-DE"); const filteredConsumersForSlot = query ? baseConsumersForSlot.filter((consumer) => { const searchable = [ consumer.circuitNumber ?? "", consumer.description ?? "", consumer.name ?? "", consumer.category ?? "", consumer.note ?? "", consumer.roomNumber ?? "", consumer.roomName ?? "", consumer.floorName ?? "", ] .join(" ") .toLocaleLowerCase("de-DE"); return searchable.includes(query); }) : baseConsumersForSlot; const listConsumersForSlot = [...filteredConsumersForSlot].sort((a, b) => { const aValue = getComparableSortValue(a, currentFilter.sortField); const bValue = getComparableSortValue(b, currentFilter.sortField); let result = 0; if (typeof aValue === "number" && typeof bValue === "number") { result = aValue - bValue; } else { result = String(aValue).localeCompare(String(bValue), "de-DE", { sensitivity: "base" }); } return currentFilter.sortDirection === "asc" ? result : result * -1; }); const quickForm = quickCreateForms[slotIndex]; return (
Liste {slotIndex + 1} {listConsumersForSlot.length}
handleCreateManualConsumer(slotIndex, event)}>
updateQuickCreateForm(slotIndex, { name: event.target.value })} />
updateQuickCreateForm(slotIndex, { quantity: event.target.value })} placeholder="Anzahl" />
updateQuickCreateForm(slotIndex, { installedPowerPerUnitKw: event.target.value }) } placeholder="Einzelleistung" />
updateQuickCreateForm(slotIndex, { demandFactor: event.target.value })} placeholder="Gleichzeitigkeitsfaktor" />
updateTotalPower(slotIndex, event.target.value)} placeholder="Gesamtleistung" />
updateQuickCreateForm(slotIndex, { addCount: event.target.value })} title="Anzahl Einträge" style={{ maxWidth: "8rem" }} />
updateListFilter(slotIndex, { query: event.target.value })} />
updateBulkEditForm(slotIndex, { quantity: event.target.value })} />
updateBulkEditForm(slotIndex, { installedPowerPerUnitKw: event.target.value }) } />
updateBulkEditForm(slotIndex, { demandFactor: event.target.value })} />
Gefiltert: {listConsumersForSlot.length} von {baseConsumersForSlot.length}
{renderedColumns.map((column) => ( ))} {listConsumersForSlot.map((consumer) => ( {renderedColumns.map((column) => { switch (column.key) { case "selection": return ( ); case "circuitNumber": return ( ); case "description": return ( ); case "name": return ( ); case "projectDevice": return ( ); case "deviceLink": return ( ); case "room": return ( ); case "floor": return ; case "category": return ( ); case "deviceType": return ( ); case "phaseType": return ( ); case "tradeOrCostGroup": return ( ); case "group": return ( ); case "protectionType": return ( ); case "protectionRatedCurrent": return ( ); case "protectionCharacteristic": return ( ); case "cableType": return ( ); case "cableCrossSection": return ( ); case "comment": return ( ); case "quantity": return ( ); case "installedPowerPerUnitKw": return ( ); case "installedPowerKw": return ; case "demandFactor": return ( ); case "demandPowerKw": return ; case "voltageV": return ; case "phaseCount": return ( ); case "powerFactor": return ( ); case "currentA": return ; case "note": return ( ); case "actions": return ( ); default: return null; } })} ))} {!listConsumersForSlot.length ? ( ) : null}
{column.label}
toggleConsumerSelection(slotIndex, consumer.id)} /> event.target.value !== (consumer.circuitNumber ?? "") ? handleInlineUpdateFields(consumer, { circuitNumber: event.target.value || undefined, }) : undefined } /> event.target.value !== (consumer.description ?? consumer.name) ? handleInlineUpdateFields(consumer, { description: event.target.value || undefined, }) : undefined } /> event.target.value !== consumer.name ? handleInlineUpdateFields(consumer, { name: event.target.value }) : undefined } /> {consumer.floorName ?? "-"} event.target.value !== (consumer.category ?? "") ? handleInlineUpdateFields(consumer, { category: event.target.value || undefined, }) : undefined } /> { const raw = event.target.value.trim(); const value = raw ? Number(raw) : undefined; if (raw === "" && consumer.protectionRatedCurrent !== undefined) { void handleInlineUpdateFields(consumer, { protectionRatedCurrent: undefined, }); } else if ( value !== undefined && !Number.isNaN(value) && value !== consumer.protectionRatedCurrent ) { void handleInlineUpdateFields(consumer, { protectionRatedCurrent: value }); } }} /> event.target.value !== (consumer.comment ?? "") ? handleInlineUpdateFields(consumer, { comment: event.target.value || undefined, }) : undefined } /> { const value = Number(event.target.value); if (!Number.isNaN(value) && value !== consumer.quantity) { void handleInlineUpdateFields(consumer, { quantity: value }); } }} /> { const value = Number(event.target.value); if (!Number.isNaN(value) && value !== consumer.installedPowerPerUnitKw) { void handleInlineUpdateFields(consumer, { installedPowerPerUnitKw: value }); } }} /> {formatNumber(consumer.installedPowerKw)} { const value = Number(event.target.value); if (!Number.isNaN(value) && value !== consumer.demandFactor) { void handleInlineUpdateFields(consumer, { demandFactor: value }); } }} /> {formatNumber(consumer.demandPowerKw)}{formatNumber(consumer.effectiveVoltageV, 0)} { const raw = event.target.value.trim(); const value = raw ? Number(raw) : undefined; if (raw === "" && consumer.powerFactor !== undefined) { void handleInlineUpdateFields(consumer, { powerFactor: undefined }); } else if (!Number.isNaN(value) && value !== consumer.powerFactor) { void handleInlineUpdateFields(consumer, { powerFactor: value }); } }} /> {consumer.currentA?.toFixed(2) ?? "-"} event.target.value !== (consumer.note ?? "") ? handleInlineUpdateFields(consumer, { note: event.target.value || undefined }) : undefined } />
{slots.slice(0, activeListCount).map((_, targetSlotIndex) => ( ))}
Keine Einträge für {slot.boardId ? boardById.get(slot.boardId)?.name : "diese Liste"}.
Ausgewählt: {slot.selectedConsumerIds.length}
{slots.slice(0, activeListCount).map((_, targetSlotIndex) => ( ))}
); })}
); }