Files
CPLv4.0/components/main/kabelueberwachung/kue705FO/Kue705FO.tsx

507 lines
18 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client"; // components/modules/kue705FO/Kue705FO.tsx
import React, { useState, useMemo } from "react";
import { useSelector } from "react-redux";
import KueModal from "./modals/SettingsModalWrapper";
// import FallSensors from "../../fall-detection-sensors/FallSensors";
import "bootstrap-icons/font/bootstrap-icons.css"; // Import Bootstrap Icons
import { Kue705FOProps } from "../../../../types/Kue705FOProps";
// Import the new specialized ChartView components
import IsoChartView from "./Charts/IsoMeasurementChart/IsoChartView";
import LoopChartView from "./Charts/LoopMeasurementChart/LoopChartView";
import TDRChartView from "./Charts/TDRChart/TDRChartView";
import KVZChartView from "./Charts/KVZChart/KVZChartView";
import SlotActivityOverlay from "./SlotActivityOverlay";
// Keep ChartSwitcher import for backwards compatibility if needed
// import ChartSwitcher from "./Charts/ChartSwitcher";
// Remove separate chart imports since we use ChartView components
// import IsoMeasurementChart from "./Charts/IsoMeasurementChart/IsoMeasurementChart";
// import LoopMeasurementChart from "./Charts/LoopMeasurementChart/LoopMeasurementChart";
//-------Redux Toolkit--------
import { RootState } from "../../../../redux/store";
import { useDispatch } from "react-redux";
//-------hooks----------------
import useAlarmStatus from "./hooks/useAlarmStatus";
import useKueVersion from "./hooks/useKueVersion";
import useIsoDisplay from "./hooks/useIsoDisplay";
import useLoopDisplay from "./hooks/useLoopDisplay";
import useModulName from "./hooks/useModulName";
import { useAdminAuth } from "../../settingsPageComponents/hooks/useAdminAuth";
//--------handlers----------------
// Keep needed imports
import handleOpenModal from "./handlers/handleOpenModal";
import handleCloseModal from "./handlers/handleCloseModal";
// Remove unused chart modal handlers since we use direct ChartView components
// import handleOpenChartModal from "./handlers/handleOpenChartModal";
// import handleCloseChartModal from "./handlers/handleCloseChartModal";
// import handleRefreshClick from "./handlers/handleRefreshClick";
const Kue705FO: React.FC<Kue705FOProps> = ({
isolationswert,
schleifenwiderstand,
modulName,
kueOnline,
slotIndex,
}) => {
/* console.log(
`Rendering Kue705FO - SlotIndex: ${slotIndex}, ModulName: ${modulName}`
); */
const dispatch = useDispatch();
const { kueName } = useSelector((state: RootState) => state.kueDataSlice);
// Admin authentication hook for security - using showModal as true for continuous auth check
const { isAdminLoggedIn } = useAdminAuth(true);
const [activeButton, setActiveButton] = useState<"Schleife" | "TDR" | "ISO">(
"Schleife"
);
const [, setloopTitleText] = useState("Schleifenwiderstand [kOhm]");
const [isoDisplayText] = useState("Aderbruch");
const [groundFaultDisplayText] = useState("Erdschluss");
const [loopFaultDisplayText] = useState("Schleifenfehler");
const [isoFaultDisplayText] = useState("Isolationsfehler");
const [isoGreaterThan200] = useState(">200 MOhm");
const [showModal, setShowModal] = useState(false);
// Separate modal states for each ChartView
const [showIsoModal, setShowIsoModal] = useState(false);
const [showRslModal, setShowRslModal] = useState(false);
const [showTdrModal, setShowTdrModal] = useState(false);
const [showKvzModal, setShowKvzModal] = useState(false);
// Keep original showChartModal for backwards compatibility if needed
// const [showChartModal, setShowChartModal] = useState(false);
// Removed unused loopMeasurementCurveChartData state
//------- Redux-Variablen abrufen--------------------------------
const {
kueVersion: reduxKueVersion,
kueCableBreak: kueCableBreakRaw,
kueGroundFault: kueGroundFaultRaw,
kueAlarm1: kueAlarm1Raw,
kueAlarm2: kueAlarm2Raw,
kueOverflow: kueOverflowRaw,
kuePSTmMinus96V, // <- richtig, weil so im State vorhanden
tdrActive, // <- TDR aktiv Status hinzugefügt
kvzPresence, // <- KVz Presence Array hinzugefügt
kvzActive, // <- KVz Active Array hinzugefügt
// kvzStatus, // <- KVz LED Status Array (jetzt nur im KVZ Modal verwendet)
} = useSelector((state: RootState) => state.kueDataSlice);
//---------------------------------------------
const kueCableBreak = useMemo(
() => kueCableBreakRaw?.map(Number) ?? [],
[kueCableBreakRaw]
);
const kueGroundFault = useMemo(
() => kueGroundFaultRaw?.map(Number) ?? [],
[kueGroundFaultRaw]
);
const kueAlarm1 = useMemo(
() => kueAlarm1Raw?.map(Number) ?? [],
[kueAlarm1Raw]
);
const kueAlarm2 = useMemo(
() => kueAlarm2Raw?.map(Number) ?? [],
[kueAlarm2Raw]
);
const kueOverflow = useMemo(
() => kueOverflowRaw?.map(Number) ?? [],
[kueOverflowRaw]
);
//-------------------------handlers-------------------------
const openModal = () => handleOpenModal(setShowModal);
const closeModal = () => handleCloseModal(setShowModal);
// New ChartView handlers - direct modal opening
const openIsoModal = () => {
setActiveButton("ISO");
// Set Redux state for ISO type
dispatch({
type: "kabelueberwachungChart/setSelectedSlotType",
payload: 1, // 1 = Isolationswiderstand
});
dispatch({
type: "kabelueberwachungChart/setSlotNumber",
payload: slotIndex,
});
setShowIsoModal(true);
};
const closeIsoModal = () => {
setShowIsoModal(false);
};
const openRslModal = () => {
setActiveButton("Schleife");
setloopTitleText("Schleifenwiderstand [kOhm]");
setLoopDisplayValue(Number(schleifenwiderstand));
dispatch({
type: "kabelueberwachungChart/setSelectedSlotType",
payload: 2,
}); // RSL type
dispatch({
type: "kabelueberwachungChart/setSlotNumber",
payload: slotIndex,
});
setShowRslModal(true);
};
const closeRslModal = () => {
setShowRslModal(false);
};
const openTdrModal = () => {
setActiveButton("TDR");
setloopTitleText("Entfernung [km]");
const latestTdrDistanceMeters =
Array.isArray(tdmChartData?.[slotIndex]) &&
tdmChartData[slotIndex].length > 0 &&
typeof tdmChartData[slotIndex][0].d === "number"
? tdmChartData[slotIndex][0].d
: 0;
const latestTdrDistance = Number(
(latestTdrDistanceMeters / 1000).toFixed(3)
);
setLoopDisplayValue(latestTdrDistance);
setShowTdrModal(true);
};
const closeTdrModal = () => {
setShowTdrModal(false);
};
const openKvzModal = () => {
setShowKvzModal(true);
};
const closeKvzModal = () => setShowKvzModal(false);
//----------------------------------
//hooks einbinden
const kueVersion = useKueVersion(slotIndex, reduxKueVersion);
const currentAlarmStatus = useAlarmStatus(
slotIndex,
kueAlarm1,
kueAlarm2,
kueCableBreak,
kueGroundFault
);
const isoDisplayValue = useIsoDisplay(
slotIndex,
!!kuePSTmMinus96V?.[slotIndex],
!!kueCableBreak?.[slotIndex],
!!kueGroundFault?.[slotIndex],
!!kueAlarm1?.[slotIndex],
!!kueAlarm2?.[slotIndex],
!!kueOverflow?.[slotIndex],
Number(isolationswert),
isoDisplayText,
groundFaultDisplayText,
isoFaultDisplayText,
loopFaultDisplayText,
isoGreaterThan200
);
const { setCurrentModulName } = useModulName(slotIndex, modulName);
//---------------------------------
//---------------------------------
const tdmChartData = useSelector(
(state: RootState) => state.tdmChartSlice.data
);
const latestTdrDistanceMeters =
Array.isArray(tdmChartData?.[slotIndex]) &&
tdmChartData[slotIndex].length > 0 &&
typeof tdmChartData[slotIndex][0].d === "number"
? tdmChartData[slotIndex][0].d
: 0;
const latestTdrDistance = Number((latestTdrDistanceMeters / 1000).toFixed(3));
//setLoopDisplayValue(latestTdrDistance);
//---------------------------------
const loopValue =
activeButton === "TDR"
? latestTdrDistance
: typeof schleifenwiderstand === "number"
? schleifenwiderstand
: Number(schleifenwiderstand);
const { loopDisplayValue, setLoopDisplayValue } = useLoopDisplay(
loopValue,
activeButton
);
// TDR aktiv Status für diesen Slot prüfen
const isTdrActiveForSlot = tdrActive?.[slotIndex] === 1;
// KVz aktiv Status für diesen Slot prüfen - nur wenn Admin authentifiziert ist, KVz vorhanden ist UND aktiviert ist
const isKvzActiveForSlot =
kvzPresence?.[slotIndex] === 1 &&
kvzActive?.[slotIndex] === 1 &&
isAdminLoggedIn;
// Removed useChartData(loopMeasurementCurveChartData) as the state was unused
//---------------------------------
return (
<div
className="relative bg-gray-300 w-[7.25rem] h-[23.375rem] border border-gray-400 transform laptop:-translate-y-12 2xl:-translate-y-0
scale-100 sm:scale-95 md:scale-100 lg:scale-105 xl:scale-90 2xl:scale-125 top-3 qhd:scale-150 qhd:-translate-y-0"
>
{/* Per-slot activity overlay */}
<SlotActivityOverlay slotIndex={slotIndex} />
{kueOnline === 1 ? (
<>
<div className="relative w-[7.075rem] h-[15.156rem] bg-littwin-blue border-[0.094rem] border-gray-400 z-0">
<div className="flex items-start justify-between h-[1.875rem]">
<div className="relative w-[1.25rem] h-[1.25rem] bg-gray-800 flex items-center justify-center">
<span className="text-white text-[0.625rem]">
{slotIndex + 1}
</span>
</div>
<h3 className="text-white font-bold text-[0.563rem] mr-[1rem]">
KÜ705-FO
</h3>
<button
onClick={openModal}
className="w-[0.938rem] h-[0.938rem] bg-gray-400 flex items-center justify-center"
>
<span className="text-white text-[1.25rem]"></span>
</button>
</div>
{}
{showModal && (
<KueModal
key={`${slotIndex}-${Date.now()}`} // ← immer neuer Schlüssel → erzwingt Remount
showModal={showModal}
onClose={closeModal}
slot={slotIndex}
onModulNameChange={setCurrentModulName}
/>
)}
<div className="flex flex-col mt-[0.625rem] ml-[0.625rem]">
<div className="flex items-center space-x-[0.25rem] mt-[0.625rem]">
<div className="flex flex-col items-start space-y-[0.063rem] mr-[0.063rem]">
<span className="text-white text-[0.625rem]">Betrieb</span>
<span className="text-white text-[0.625rem]">Alarm</span>
</div>
<div className="flex flex-col items-center space-y-[0.188rem]">
<div className="w-[0.625rem] h-[0.625rem] bg-green-500 rounded-full"></div>
<div
className={`w-[0.625rem] h-[0.625rem] rounded-full ${
currentAlarmStatus ? "bg-red-500" : "bg-gray-300"
}`}
></div>
</div>
</div>
</div>
{/* Schwarzes Display mit drei Zeilen: Alarm, ISO, Schleife */}
<div className="relative mt-[3.125rem] mx-auto bg-black text-white w-[6.8rem] h-[3.1rem] flex flex-col items-center justify-between z-10 p-1">
<div className="text-center w-full flex flex-col justify-between items-center h-full">
{/* 1. Zeile: Alarmtext in Rot, sonst "Status: OK" */}
<span
className={`whitespace-nowrap block text-[0.65rem] font-semibold ${
Number(kuePSTmMinus96V?.[slotIndex]) === 1 ||
Number(kueCableBreak?.[slotIndex]) === 1 ||
Number(kueGroundFault?.[slotIndex]) === 1 ||
Number(kueAlarm1?.[slotIndex]) === 1 ||
Number(kueAlarm2?.[slotIndex]) === 1
? "text-red-500"
: "text-green-500"
}`}
>
{Number(kuePSTmMinus96V?.[slotIndex]) === 1
? "Messpannung"
: Number(kueCableBreak?.[slotIndex]) === 1
? "Aderbruch"
: Number(kueGroundFault?.[slotIndex]) === 1
? "Erdschluss"
: Number(kueAlarm1?.[slotIndex]) === 1
? "Isolationsfehler"
: Number(kueAlarm2?.[slotIndex]) === 1
? "Schleifenfehler"
: " "}
{"\u00A0"}
{/* Status: OK*/}
</span>
{/* 2. Zeile: ISO-Wert, immer anzeigen */}
<span
className={`whitespace-nowrap block text-[0.65rem] font-semibold ${
Number(kueAlarm1?.[slotIndex]) === 1 ? "text-red-500" : ""
}`}
>
{isoDisplayValue === "Abgleich"
? "ISO: Abgleich"
: `ISO: ${Number(isolationswert)
.toFixed(2)
.replace(".", ",")} MOhm`}
</span>
{/* 3. Zeile: Schleifenwert, in Rot bei Schleifenfehler, sonst normal */}
<span
className={`whitespace-nowrap block text-[0.65rem] font-semibold ${
Number(kueAlarm2?.[slotIndex]) === 1 ? "text-red-500" : ""
}`}
>
{`RSL: ${Number(loopDisplayValue)
.toFixed(3)
.replace(".", ",")} kOhm`}
</span>
</div>
</div>
<div className="absolute top-0 left-[4.688rem] w-[0.188rem] h-full bg-white z-0"></div>
<div className="absolute top-[2.5rem] left-[4.688rem] w-[2.5rem] h-[0.188rem] bg-white z-0"></div>
<div className="absolute bottom-[1.25rem] left-0 right-0 text-black text-[0.625rem] bg-gray-300 p-[0.063rem] text-center">
{kueName?.[slotIndex] || `Modul ${slotIndex + 1}`}
</div>
<div className="absolute bottom-[0.063rem] right-[0.063rem] text-black text-[0.5rem]">
{kueVersion}
</div>
</div>
{/* Modal für Einstellungen */}
</>
) : (
<div className="flex items-center justify-center h-full text-gray-500">
{/* Das soll rausgenommen werden
<p>Kein Modul im Slot {slotIndex + 0}</p>
*/}
</div>
)}
{/* Messkurven-Button unter dem Modul */}
{kueOnline === 1 && (
<>
{/*
Überschrift: Detailansicht
ISO und RSL als Buttons (Firmenblau) nebeneinander
TDR und KVz Buttons (Firmenblau) nebeneinander
Wenn kein TDR oder kein KVz: nur grauer Button ohne Text
*/}
<div className="flex flex-col items-center w-full px-2 mt-2 space-y-2">
{/* Detailansicht Header */}
<span className="text-black text-[0.625rem] font-semibold">
Detailansicht
</span>
{/* ISO and RSL Buttons */}
<div className="flex space-x-2">
<button
onClick={openIsoModal}
className="bg-littwin-blue text-white text-[0.625rem] flex items-center justify-center p-2 min-w-[2.5rem]"
>
ISO
</button>
<button
onClick={openRslModal}
className="bg-littwin-blue text-white text-[0.625rem] flex items-center justify-center p-2 min-w-[2.5rem]"
>
RSL
</button>
</div>
{/* TDR and KVz Buttons */}
<div className="flex space-x-2 p-1">
{/* TDR Button - blau mit Text wenn aktiv, grau ohne Text wenn inaktiv */}
<button
onClick={isTdrActiveForSlot ? openTdrModal : undefined}
className={`${
isTdrActiveForSlot
? "bg-littwin-blue text-white cursor-pointer"
: "bg-gray-400 cursor-default"
} text-[0.625rem] flex items-center justify-center p-2 min-w-[2.5rem]`}
>
{isTdrActiveForSlot ? "TDR" : "\u00A0\u00A0\u00A0"}
</button>
{/* KVz Button - blau mit Text wenn aktiv, grau ohne Text wenn inaktiv */}
<button
onClick={isKvzActiveForSlot ? openKvzModal : undefined}
className={`${
isKvzActiveForSlot
? "bg-littwin-blue text-white cursor-pointer"
: "bg-gray-400 cursor-default"
} text-[0.625rem] flex items-center justify-center p-2 min-w-[2.5rem]`}
disabled={!isKvzActiveForSlot}
title={
isKvzActiveForSlot ? "KVZ öffnen" : "KVZ nicht verfügbar"
}
>
{isKvzActiveForSlot ? "KVZ" : "\u00A0\u00A0\u00A0"}
</button>
</div>
{/* Messkurve Button */}
{/* TDR Messkurve und Schleife Messkurve Buttons */}
<div className="flex flex-col space-y-2 w-full"></div>
</div>
{/* ISO Chart Modal */}
<div className="absolute bottom-0 left-0 right-0 h-[0.125rem] bg-gray-400"></div>
{/* ISO Chart Modal */}
<IsoChartView
isOpen={showIsoModal}
onClose={closeIsoModal}
slotIndex={slotIndex}
/>
{/* RSL Chart Modal */}
<LoopChartView
isOpen={showRslModal}
onClose={closeRslModal}
slotIndex={slotIndex}
/>
{/* TDR Chart Modal - nur wenn TDR aktiv ist */}
{isTdrActiveForSlot && (
<TDRChartView
isOpen={showTdrModal}
onClose={closeTdrModal}
slotIndex={slotIndex}
/>
)}
{isKvzActiveForSlot && (
<KVZChartView
isOpen={showKvzModal}
onClose={closeKvzModal}
slotIndex={slotIndex}
/>
)}
</>
)}
{/* Früher inline Panel jetzt eigenes Modal (KVZChartView) */}
{/* {showKvzPanel && isKvzActiveForSlot && (
<div className="flex flex-col items-center ">
<FallSensors slotIndex={slotIndex} />
</div>
)} */}
{/* Offline-View */}
{kueOnline !== 1 && (
<div className="flex items-center justify-center ">
{/* Das soll rausgenommen werden
<p>Kein Modul im Slot {slotIndex + 0}</p>
*/}
</div>
)}
</div>
);
};
export default Kue705FO;