- Lokale useState-Variablen für alle Eingabefelder in KueEinstellung.tsx eingeführt
- Fokusverlust beim Tippen verhindert, Redux-Update erfolgt erst bei onBlur
- handleSave.ts angepasst: Jede Änderung wird einzeln als CGI-Request gesendet
- Fehlerhafte Namensspeicherung ("Test;KL_0=13") korrigiert
- Zuverlässigkeit der Bedienung und Speicherung auf CPL-Webserver verbessert
299 lines
9.2 KiB
TypeScript
299 lines
9.2 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { useDispatch, useSelector } from "react-redux";
|
|
import type { RootState } from "../../../../../redux/store";
|
|
import { setKueData } from "../../../../../redux/slices/kueDataSlice";
|
|
import handleSave, { OriginalValues } from "../handlers/handleSave";
|
|
import handleDisplayEinschalten from "../handlers/handleDisplayEinschalten";
|
|
import firmwareUpdate from "../handlers/firmwareUpdate";
|
|
import { useAdminAuth } from "../../../settingsPageComponents/hooks/useAdminAuth";
|
|
|
|
declare global {
|
|
interface Window {
|
|
win_kueID?: string[];
|
|
win_kueLimit1?: number[];
|
|
win_kueDelay1?: number[];
|
|
win_kueLimit2Low?: number[];
|
|
win_kueLimit2High?: number[];
|
|
win_kueLoopInterval?: number[];
|
|
win_memoryInterval?: number[];
|
|
}
|
|
}
|
|
|
|
interface Props {
|
|
slot: number;
|
|
onClose?: () => void;
|
|
onModulNameChange?: (id: string) => void;
|
|
}
|
|
|
|
const memoryIntervalOptions = [
|
|
{ value: 0, label: "Kein" },
|
|
{ value: 1, label: "1 Minute" },
|
|
{ value: 5, label: "5 Minuten" },
|
|
{ value: 10, label: "10 Minuten" },
|
|
{ value: 15, label: "15 Minuten" },
|
|
{ value: 30, label: "30 Minuten" },
|
|
{ value: 60, label: "60 Minuten" },
|
|
{ value: 360, label: "6 Stunden" },
|
|
{ value: 720, label: "12 Stunden" },
|
|
];
|
|
|
|
export default function KueEinstellung({
|
|
slot,
|
|
onClose = () => {},
|
|
onModulNameChange = () => {},
|
|
}: Props) {
|
|
const dispatch = useDispatch();
|
|
const {
|
|
kueID,
|
|
kueLimit1,
|
|
kueDelay1,
|
|
kueLimit2Low,
|
|
kueLimit2High,
|
|
kueLoopInterval,
|
|
memoryInterval,
|
|
} = useSelector((state: RootState) => state.kueDataSlice);
|
|
|
|
const { isAdminLoggedIn } = useAdminAuth(true);
|
|
|
|
// Lokale States
|
|
const [localName, setLocalName] = useState(kueID[slot] || "");
|
|
const [localLimit1, setLocalLimit1] = useState<number | "">(
|
|
kueLimit1[slot] ?? ""
|
|
);
|
|
const [localDelay1, setLocalDelay1] = useState<number | "">(
|
|
kueDelay1[slot] ?? ""
|
|
);
|
|
const [localLimit2Low, setLocalLimit2Low] = useState<number | "">(
|
|
kueLimit2Low[slot] ?? ""
|
|
);
|
|
const [localLoopInterval, setLocalLoopInterval] = useState<number | "">(
|
|
kueLoopInterval[slot] ?? ""
|
|
);
|
|
const [localMemoryInterval, setLocalMemoryInterval] = useState<number | "">(
|
|
memoryInterval[slot] ?? ""
|
|
);
|
|
|
|
useEffect(() => {
|
|
setLocalName(kueID[slot] || "");
|
|
setLocalLimit1(kueLimit1[slot] ?? "");
|
|
setLocalDelay1(kueDelay1[slot] ?? "");
|
|
setLocalLimit2Low(kueLimit2Low[slot] ?? "");
|
|
setLocalLoopInterval(kueLoopInterval[slot] ?? "");
|
|
setLocalMemoryInterval(memoryInterval[slot] ?? "");
|
|
}, [
|
|
kueID,
|
|
kueLimit1,
|
|
kueDelay1,
|
|
kueLimit2Low,
|
|
kueLoopInterval,
|
|
memoryInterval,
|
|
slot,
|
|
]);
|
|
|
|
const handleSaveWrapper = () => {
|
|
const originalValues: OriginalValues = {
|
|
kueID: [...(window.win_kueID ?? [])],
|
|
isolationsgrenzwerte: [...(window.win_kueLimit1 ?? [])],
|
|
verzoegerung: [...(window.win_kueDelay1 ?? [])],
|
|
untereSchleifenGrenzwerte: [...(window.win_kueLimit2Low ?? [])],
|
|
obereSchleifenGrenzwerte: [...(window.win_kueLimit2High ?? [])],
|
|
schleifenintervall: [...(window.win_kueLoopInterval ?? [])],
|
|
speicherintervall: [...(window.win_memoryInterval ?? [])],
|
|
};
|
|
|
|
handleSave({
|
|
ids: [...kueID],
|
|
isolationsgrenzwerte: [...kueLimit1],
|
|
verzoegerung: [...kueDelay1],
|
|
untereSchleifenGrenzwerte: [...kueLimit2Low],
|
|
obereSchleifenGrenzwerte: [...kueLimit2High],
|
|
schleifenintervall: [...kueLoopInterval],
|
|
speicherintervall: [...memoryInterval],
|
|
originalValues,
|
|
slot,
|
|
dispatch,
|
|
onModulNameChange,
|
|
onClose,
|
|
});
|
|
};
|
|
|
|
const updateRedux = () => {
|
|
dispatch(
|
|
setKueData({
|
|
kueID: [...kueID.slice(0, slot), localName, ...kueID.slice(slot + 1)],
|
|
kueLimit1: [
|
|
...kueLimit1.slice(0, slot),
|
|
Number(localLimit1),
|
|
...kueLimit1.slice(slot + 1),
|
|
],
|
|
kueDelay1: [
|
|
...kueDelay1.slice(0, slot),
|
|
Number(localDelay1),
|
|
...kueDelay1.slice(slot + 1),
|
|
],
|
|
kueLimit2Low: [
|
|
...kueLimit2Low.slice(0, slot),
|
|
Number(localLimit2Low),
|
|
...kueLimit2Low.slice(slot + 1),
|
|
],
|
|
kueLoopInterval: [
|
|
...kueLoopInterval.slice(0, slot),
|
|
Number(localLoopInterval),
|
|
...kueLoopInterval.slice(slot + 1),
|
|
],
|
|
memoryInterval: [
|
|
...memoryInterval.slice(0, slot),
|
|
Number(localMemoryInterval),
|
|
...memoryInterval.slice(slot + 1),
|
|
],
|
|
})
|
|
);
|
|
};
|
|
|
|
return (
|
|
<div className="text-black space-y-6">
|
|
<div>
|
|
<label className="font-bold">Kabelbezeichnung:</label>
|
|
<input
|
|
type="text"
|
|
className="w-full border rounded p-1 text-sm"
|
|
value={localName}
|
|
onChange={(e) => setLocalName(e.target.value)}
|
|
onBlur={updateRedux}
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<h3 className="font-bold text-center mb-2">Isolationsmessung</h3>
|
|
<table className="w-full border-collapse text-sm">
|
|
<thead className="bg-gray-100">
|
|
<tr>
|
|
<th className="border p-2 text-center">Grenzwert (MOhm)</th>
|
|
<th className="border p-2 text-center">Verzögerung (sek)</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td className="border p-2 text-center">
|
|
<input
|
|
type="number"
|
|
step="0.1"
|
|
className="w-[6rem] border rounded p-1"
|
|
value={localLimit1}
|
|
onChange={(e) =>
|
|
setLocalLimit1(
|
|
e.target.value ? parseFloat(e.target.value) : ""
|
|
)
|
|
}
|
|
onBlur={updateRedux}
|
|
/>
|
|
</td>
|
|
<td className="border p-2 text-center">
|
|
<input
|
|
type="number"
|
|
step="0.1"
|
|
className="w-[6rem] border rounded p-1"
|
|
value={localDelay1}
|
|
onChange={(e) =>
|
|
setLocalDelay1(
|
|
e.target.value ? parseFloat(e.target.value) : ""
|
|
)
|
|
}
|
|
onBlur={updateRedux}
|
|
/>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div>
|
|
<h3 className="font-bold text-center mb-2">Schleifenmessung</h3>
|
|
<table className="w-full border-collapse text-sm mb-2">
|
|
<thead className="bg-gray-100">
|
|
<tr>
|
|
<th className="border p-2 text-center">Grenzwert (kOhm)</th>
|
|
<th className="border p-2 text-center">Schleifenintervall (h)</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td className="border p-2 text-center">
|
|
<input
|
|
type="number"
|
|
step="0.1"
|
|
className="w-[6rem] border rounded p-1"
|
|
value={localLimit2Low}
|
|
onChange={(e) =>
|
|
setLocalLimit2Low(
|
|
e.target.value ? parseFloat(e.target.value) : ""
|
|
)
|
|
}
|
|
onBlur={updateRedux}
|
|
/>
|
|
</td>
|
|
<td className="border p-2 text-center">
|
|
<input
|
|
type="number"
|
|
step="0.1"
|
|
className="w-[6rem] border rounded p-1"
|
|
value={localLoopInterval}
|
|
onChange={(e) =>
|
|
setLocalLoopInterval(
|
|
e.target.value ? parseFloat(e.target.value) : ""
|
|
)
|
|
}
|
|
onBlur={updateRedux}
|
|
/>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<div>
|
|
<label className="font-bold block mb-1">Speicherintervall</label>
|
|
<select
|
|
className="w-full border rounded p-1 text-sm"
|
|
value={localMemoryInterval}
|
|
onChange={(e) =>
|
|
setLocalMemoryInterval(parseInt(e.target.value, 10))
|
|
}
|
|
onBlur={updateRedux}
|
|
>
|
|
{memoryIntervalOptions.map((opt) => (
|
|
<option key={opt.value} value={opt.value}>
|
|
{opt.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex justify-end gap-2 bg-gray-100 p-3 rounded">
|
|
{isAdminLoggedIn && (
|
|
<button
|
|
onClick={() => firmwareUpdate(slot)}
|
|
className="bg-littwin-blue text-white px-4 py-2 rounded flex items-center"
|
|
>
|
|
<span className="mr-2">🔧</span> Firmware Update
|
|
</button>
|
|
)}
|
|
<button
|
|
onClick={() => handleDisplayEinschalten(slot)}
|
|
className="bg-littwin-blue text-white px-4 py-2 rounded flex items-center"
|
|
>
|
|
<span className="mr-2">📺</span> Display einschalten
|
|
</button>
|
|
<button
|
|
onClick={handleSaveWrapper}
|
|
className="bg-littwin-blue text-white px-4 py-2 rounded flex items-center"
|
|
>
|
|
<span className="mr-2">💾</span> Speichern
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|