- `fetchAnalogeEingaengeThunk` in `AnalogeEingaengeTable.tsx` verwendet, um API-Daten in Redux zu speichern.
- `useFetchAnalogeEingaenge` entfernt, um doppelte API-Aufrufe zu vermeiden.
- Sicherstellung, dass Redux-Thunk nur im Client (`useEffect`) ausgeführt wird.
- Automatische Aktualisierung der API-Daten alle 10 Sekunden über Redux-Thunk.
- Code-Optimierungen für eine stabilere Client-Side-Architektur mit Next.js.
✅ Jetzt läuft Redux-Thunk stabil & effizient in der Next.js-Anwendung!
132 lines
4.9 KiB
TypeScript
132 lines
4.9 KiB
TypeScript
"use client"; // components/main/analogeEingaenge/AnalogeEingaengeTable.tsx
|
||
import React, { useEffect, useState } from "react";
|
||
import { useDispatch, useSelector } from "react-redux";
|
||
import { RootState, AppDispatch } from "../../../redux/store";
|
||
import { fetchAnalogeEingaengeThunk } from "../../../redux/thunks/fetchAnalogeEingaengeThunk";
|
||
|
||
export default function AnalogeEingaengeTable() {
|
||
const dispatch = useDispatch<AppDispatch>();
|
||
|
||
useEffect(() => {
|
||
dispatch(fetchAnalogeEingaengeThunk()); // ✅ Holt die API-Daten nur im Client
|
||
}, [dispatch]);
|
||
|
||
const analogeEingaenge = useSelector(
|
||
(state: RootState) => state.analogeEingaenge
|
||
);
|
||
|
||
const [selectedEingang, setSelectedEingang] = useState(null);
|
||
|
||
const openSettingsModal = (eingang: any) => {
|
||
setSelectedEingang(eingang);
|
||
};
|
||
|
||
const closeSettingsModal = () => {
|
||
setSelectedEingang(null);
|
||
};
|
||
|
||
return (
|
||
<div className="w-full">
|
||
<div className="bg-white shadow-lg rounded-lg p-4 border border-gray-200">
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full border-collapse border border-gray-300 text-sm md:text-base">
|
||
<thead>
|
||
<tr className="bg-gray-100 text-gray-700">
|
||
<th className="border p-1 text-left">Eingang</th>
|
||
<th className="border p-3 text-left">Wert</th>
|
||
<th className="border p-3 text-left">Bezeichnung</th>
|
||
<th className="border p-3 text-center">uW</th>
|
||
<th className="border p-3 text-center">uG</th>
|
||
<th className="border p-3 text-center">oW</th>
|
||
<th className="border p-3 text-center">oG</th>
|
||
<th className="border p-3 text-center">Einstellung</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{Object.values(analogeEingaenge).map((eingang, index) => (
|
||
<tr
|
||
key={index}
|
||
className="text-gray-700 hover:bg-gray-50 transition"
|
||
>
|
||
<td className="border p-3">{eingang.id ?? "-"}</td>
|
||
<td className="border p-3">{eingang.value ?? "-"}</td>
|
||
<td className="border p-3">{eingang.name || "----"}</td>
|
||
<td className="border p-3 text-center">
|
||
{eingang.uW ? "🟢" : "⚪"}
|
||
</td>
|
||
<td className="border p-3 text-center">
|
||
{eingang.uG ? "🟢" : "⚪"}
|
||
</td>
|
||
<td className="border p-3 text-center">
|
||
{eingang.oW ? "🟠" : "⚪"}
|
||
</td>
|
||
<td className="border p-3 text-center">
|
||
{eingang.oG ? "🟢" : "⚪"}
|
||
</td>
|
||
<td className="border p-3 text-center">
|
||
<button
|
||
onClick={() => openSettingsModal(eingang)}
|
||
className="bg-blue-500 text-white text-xs px-2 py-1 rounded hover:bg-blue-600 transition"
|
||
>
|
||
⚙️
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Modal */}
|
||
{selectedEingang && (
|
||
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
|
||
<div className="bg-white p-6 rounded-lg shadow-lg w-3/4 max-w-3xl">
|
||
<div className="flex justify-between items-center border-b pb-2">
|
||
<h2 className="text-lg font-bold text-gray-700">
|
||
Analoge Eingänge Einstellungen
|
||
</h2>
|
||
<button onClick={closeSettingsModal} className="text-gray-500">
|
||
❌
|
||
</button>
|
||
</div>
|
||
|
||
<div className="mt-4">
|
||
<label className="block text-sm text-gray-700">Eingang:</label>
|
||
<input
|
||
type="text"
|
||
className="w-full border px-2 py-1 rounded"
|
||
value={selectedEingang.id}
|
||
readOnly
|
||
/>
|
||
|
||
<label className="block text-sm text-gray-700 mt-2">
|
||
Bezeichnung:
|
||
</label>
|
||
<input
|
||
type="text"
|
||
className="w-full border px-2 py-1 rounded"
|
||
defaultValue={selectedEingang.name}
|
||
/>
|
||
|
||
<label className="block text-sm text-gray-700 mt-2">Typ:</label>
|
||
<input
|
||
type="text"
|
||
className="w-full border px-2 py-1 rounded"
|
||
defaultValue="Spg."
|
||
readOnly
|
||
/>
|
||
</div>
|
||
|
||
<div className="flex justify-end mt-4">
|
||
<button className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
|
||
💾 Speichern
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|