343 lines
12 KiB
TypeScript
343 lines
12 KiB
TypeScript
"use client";
|
|
// components/main/kabelueberwachung/kue705FO/modals/KueEinstellung.tsx
|
|
import { useState } from "react";
|
|
import { useDispatch, useSelector } from "react-redux";
|
|
import type { RootState, AppDispatch } from "../../../../../redux/store";
|
|
import handleSave from "../handlers/handleSave";
|
|
import handleDisplayEinschalten from "../handlers/handleDisplayEinschalten";
|
|
import firmwareUpdate from "../handlers/firmwareUpdate";
|
|
import ProgressModal from "@/components/main/settingsPageComponents/modals/ProgressModal";
|
|
import { toast } from "react-toastify";
|
|
import ConfirmModal from "@/components/common/ConfirmModal";
|
|
import {
|
|
openConfirmModal,
|
|
closeConfirmModal,
|
|
} from "@/redux/slices/confirmModalSlice";
|
|
import { startFirmwareUpdateThunk } from "@/redux/thunks/startFirmwareUpdateThunk";
|
|
import { Listbox } from "@headlessui/react";
|
|
|
|
interface Props {
|
|
slot: number;
|
|
showModal: boolean;
|
|
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<AppDispatch>();
|
|
const {
|
|
kueID,
|
|
kueName,
|
|
kueLimit1,
|
|
kueDelay1,
|
|
kueLimit2Low,
|
|
kueLoopInterval,
|
|
memoryInterval,
|
|
} = useSelector((state: RootState) => state.kueDataSlice);
|
|
const reduxAdmin = useSelector(
|
|
(state: RootState) => state.authSlice.isAdminLoggedIn
|
|
);
|
|
const [isAdminLoggedIn] = useState(() => reduxAdmin);
|
|
|
|
const showConfirmModal = useSelector(
|
|
(state: RootState) => state.confirmModal.open
|
|
);
|
|
|
|
const isUpdating = useSelector(
|
|
(state: RootState) => state.firmwareProgress.isUpdating
|
|
);
|
|
const progress = useSelector(
|
|
(state: RootState) => state.firmwareProgress.progress
|
|
);
|
|
|
|
const [formData, setFormData] = useState(() => {
|
|
if (typeof window !== "undefined") {
|
|
const cache = window.__kueCache?.[`slot_${slot}`];
|
|
if (cache) return cache;
|
|
}
|
|
return {
|
|
kueID: kueID[slot] || "",
|
|
kueName: kueName[slot] || "",
|
|
limit1: kueLimit1[slot]?.toString() ?? "",
|
|
delay1: kueDelay1[slot]?.toString() ?? "",
|
|
limit2Low: kueLimit2Low[slot]?.toString() ?? "",
|
|
loopInterval: kueLoopInterval[slot]?.toString() ?? "",
|
|
memoryInterval: memoryInterval[slot]?.toString() ?? "",
|
|
};
|
|
});
|
|
|
|
const handleChange = (key: keyof typeof formData, value: string) => {
|
|
const updated = { ...formData, [key]: value };
|
|
setFormData(updated);
|
|
if (typeof window !== "undefined") {
|
|
window.__kueCache = window.__kueCache || {};
|
|
window.__kueCache[`slot_${slot}`] = updated;
|
|
}
|
|
};
|
|
|
|
const handleSaveWrapper = async () => {
|
|
const updatedKueName = [...kueName];
|
|
updatedKueName[slot] = formData.kueName;
|
|
|
|
const updatedLimit1 = [...kueLimit1];
|
|
updatedLimit1[slot] = Number(formData.limit1);
|
|
|
|
const updatedDelay1 = [...kueDelay1];
|
|
updatedDelay1[slot] = Number(formData.delay1);
|
|
|
|
const updatedLimit2Low = [...kueLimit2Low];
|
|
updatedLimit2Low[slot] = Number(formData.limit2Low);
|
|
|
|
const updatedLoopInterval = [...kueLoopInterval];
|
|
updatedLoopInterval[slot] = Number(formData.loopInterval);
|
|
|
|
const updatedMemoryInterval = [...memoryInterval];
|
|
updatedMemoryInterval[slot] = Number(formData.memoryInterval);
|
|
|
|
const newData = {
|
|
kueID: kueID[slot],
|
|
kueName: updatedKueName[slot],
|
|
limit1: updatedLimit1[slot].toString(),
|
|
delay1: updatedDelay1[slot].toString(),
|
|
limit2Low: updatedLimit2Low[slot].toString(),
|
|
loopInterval: updatedLoopInterval[slot].toString(),
|
|
memoryInterval: updatedMemoryInterval[slot].toString(),
|
|
};
|
|
setFormData(newData);
|
|
if (typeof window !== "undefined") {
|
|
window.__kueCache![`slot_${slot}`] = newData;
|
|
}
|
|
|
|
await handleSave({
|
|
slot,
|
|
ids: kueID,
|
|
kueName: updatedKueName,
|
|
isolationsgrenzwerte: updatedLimit1,
|
|
verzoegerung: updatedDelay1,
|
|
untereSchleifenGrenzwerte: updatedLimit2Low,
|
|
obereSchleifenGrenzwerte: updatedLimit2Low,
|
|
schleifenintervall: updatedLoopInterval,
|
|
speicherintervall: updatedMemoryInterval,
|
|
originalValues: {
|
|
kueID,
|
|
kueName,
|
|
isolationsgrenzwerte: kueLimit1,
|
|
verzoegerung: kueDelay1,
|
|
untereSchleifenGrenzwerte: kueLimit2Low,
|
|
obereSchleifenGrenzwerte: kueLimit2Low,
|
|
schleifenintervall: kueLoopInterval,
|
|
speicherintervall: memoryInterval,
|
|
},
|
|
dispatch,
|
|
onModulNameChange: onModulNameChange ?? (() => {}),
|
|
onClose,
|
|
});
|
|
};
|
|
|
|
return (
|
|
<div className="p-4 text-sm">
|
|
{/* Kabelbezeichnung */}
|
|
<div className="mb-4 grid grid-cols-3 items-center gap-2 w-full">
|
|
<label className="">Kabelbezeichnung:</label>
|
|
<input
|
|
type="text"
|
|
className="w-full border rounded p-1 bg-gray-100 text-gray-600"
|
|
value={formData.kueID}
|
|
readOnly
|
|
title="Feld kann nicht bearbeitet werden"
|
|
/>
|
|
</div>
|
|
{/* Kabelname */}
|
|
<div className="mb-4 grid grid-cols-3 items-center gap-2 w-full">
|
|
<label className="">Kabelname:</label>
|
|
<input
|
|
type="text"
|
|
className="w-full border rounded p-1"
|
|
value={formData.kueName}
|
|
onChange={(e) => handleChange("kueName", e.target.value)}
|
|
/>
|
|
</div>
|
|
{/* Speicherintervall */}
|
|
<div className="mb-4 grid grid-cols-3 items-center gap-2 w-full">
|
|
<label className="">Speicherintervall:</label>
|
|
<Listbox
|
|
value={formData.memoryInterval}
|
|
onChange={(value) => handleChange("memoryInterval", value)}
|
|
>
|
|
<div className="relative w-full">
|
|
<Listbox.Button className="w-full border px-3 py-1 rounded text-left bg-white flex justify-between items-center text-sm">
|
|
<span>
|
|
{memoryIntervalOptions.find(
|
|
(opt) => String(opt.value) === formData.memoryInterval
|
|
)?.label ?? "Speicherintervall wählen"}
|
|
</span>
|
|
<svg
|
|
className="w-5 h-5 text-gray-400"
|
|
viewBox="0 0 20 20"
|
|
fill="currentColor"
|
|
>
|
|
<path
|
|
fillRule="evenodd"
|
|
d="M5.23 7.21a.75.75 0 011.06.02L10 10.585l3.71-3.355a.75.75 0 111.02 1.1l-4.25 3.85a.75.75 0 01-1.02 0l-4.25-3.85a.75.75 0 01.02-1.06z"
|
|
clipRule="evenodd"
|
|
/>
|
|
</svg>
|
|
</Listbox.Button>
|
|
<Listbox.Options className="absolute z-50 mt-1 w-full border rounded bg-white shadow max-h-60 overflow-auto text-sm">
|
|
{memoryIntervalOptions.map((opt) => (
|
|
<Listbox.Option
|
|
key={opt.value}
|
|
value={String(opt.value)}
|
|
className={({ selected, active }) =>
|
|
`px-4 py-1 cursor-pointer ${
|
|
selected
|
|
? "bg-littwin-blue text-white font-medium"
|
|
: active
|
|
? "bg-gray-200"
|
|
: "text-gray-900"
|
|
}`
|
|
}
|
|
>
|
|
{opt.label}
|
|
</Listbox.Option>
|
|
))}
|
|
</Listbox.Options>
|
|
</div>
|
|
</Listbox>
|
|
</div>
|
|
|
|
{/* Isolationsmessung */}
|
|
<div className="mb-4 w-full">
|
|
<h3 className="font-bold mb-2">Isolationsmessung</h3>
|
|
<div className="mb-4 grid grid-cols-3 items-center gap-2 w-full">
|
|
<label className="w-48 ">Grenzwert:</label>
|
|
<div className="relative w-36">
|
|
<input
|
|
type="number"
|
|
className="border rounded px-2 py-1 pr-20 w-full text-right"
|
|
value={formData.limit1}
|
|
onChange={(e) => handleChange("limit1", e.target.value)}
|
|
/>
|
|
<span className="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-500 text-sm">
|
|
MOhm
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div className="mb-4 grid grid-cols-3 items-center gap-2 w-full">
|
|
<label className="w-48 ">Verzögerung:</label>
|
|
<div className="relative w-36">
|
|
<input
|
|
type="number"
|
|
className="border rounded px-2 py-1 pr-20 w-full text-right"
|
|
value={formData.delay1}
|
|
onChange={(e) => handleChange("delay1", e.target.value)}
|
|
/>
|
|
<span className="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-500 text-sm">
|
|
Sekunden
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{/* Schleifenmessung */}
|
|
<div className="mb-4">
|
|
<h3 className="font-bold mb-2">Schleifenmessung</h3>
|
|
<div className="mb-4 grid grid-cols-3 items-center gap-2 w-full">
|
|
<label className="w-48 ">Grenzwert:</label>
|
|
<div className="relative w-36">
|
|
<input
|
|
type="number"
|
|
className="border rounded px-2 py-1 pr-20 w-full text-right"
|
|
value={formData.limit2Low}
|
|
onChange={(e) => handleChange("limit2Low", e.target.value)}
|
|
/>
|
|
<span className="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-500 text-sm">
|
|
kOhm
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div className="mb-4 grid grid-cols-3 items-center gap-2 w-full">
|
|
<label className="w-48 ">Schleifenmessintervall:</label>
|
|
<div className="relative w-36">
|
|
<input
|
|
type="number"
|
|
className="border rounded px-2 py-1 pr-20 w-full text-right"
|
|
value={formData.loopInterval}
|
|
onChange={(e) => handleChange("loopInterval", e.target.value)}
|
|
/>
|
|
<span className="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-500 text-sm">
|
|
Stunden
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="flex justify-end gap-2 p-0 rounded">
|
|
{isAdminLoggedIn && (
|
|
<>
|
|
<button
|
|
onClick={() => dispatch(openConfirmModal())}
|
|
className="bg-littwin-blue text-white px-4 py-2 rounded flex items-center"
|
|
>
|
|
Firmware Update
|
|
</button>
|
|
</>
|
|
)}
|
|
{showConfirmModal && (
|
|
<ConfirmModal
|
|
open={showConfirmModal}
|
|
title="Firmware-Update starten?"
|
|
message="⚠️ Das Firmware-Update kann einige Minuten dauern. Möchten Sie wirklich fortfahren?"
|
|
onCancel={() => dispatch(closeConfirmModal())}
|
|
onConfirm={async () => {
|
|
dispatch(closeConfirmModal());
|
|
toast.info("Firmware-Update gestartet. Bitte warten...");
|
|
dispatch(startFirmwareUpdateThunk(slot)); // Start Redux-Prozess
|
|
|
|
try {
|
|
await firmwareUpdate(slot);
|
|
} catch (err) {
|
|
console.error("Firmware-Update-Fehler:", err);
|
|
toast.error("❌ Fehler beim Firmwareupdate");
|
|
}
|
|
}}
|
|
/>
|
|
)}
|
|
{isUpdating && (
|
|
<ProgressModal
|
|
visible={isUpdating}
|
|
progress={progress}
|
|
slot={slot + 1}
|
|
/>
|
|
)}
|
|
<button
|
|
onClick={() => handleDisplayEinschalten(slot)}
|
|
className="bg-littwin-blue text-white px-4 py-2 rounded flex items-center"
|
|
>
|
|
Display einschalten
|
|
</button>{" "}
|
|
<button
|
|
onClick={handleSaveWrapper}
|
|
className="bg-littwin-blue text-white px-4 py-2 rounded flex items-center"
|
|
>
|
|
Speichern
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|