Files
CPLv4.0/components/main/system/DetailModal.tsx
ISA 44cfd2ab81 refactor: Zeitraum-Dropdown in DetailModal auf Listbox mit Littwin-Design umgestellt
- <select> durch Headless UI Listbox ersetzt
- Optionen DIA0, DIA1, DIA2 mit deutschem Label dargestellt
- Einheitliches Styling mit littwin-blue wie in anderen Komponenten
2025-07-08 07:09:27 +02:00

158 lines
5.0 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.

// components/main/system/DetailModal.tsx
"use client";
import React from "react";
import { Line } from "react-chartjs-2";
import { useSelector } from "react-redux";
import { RootState } from "@/redux/store";
import { Listbox } from "@headlessui/react";
type Props = {
isOpen: boolean;
selectedKey: string | null;
onClose: () => void;
zeitraum: "DIA0" | "DIA1" | "DIA2";
setZeitraum: (typ: "DIA0" | "DIA1" | "DIA2") => void;
};
type ReduxDataEntry = { t: string; i: number };
export const DetailModal = ({
isOpen,
selectedKey,
onClose,
zeitraum,
setZeitraum,
}: Props) => {
const reduxData: ReduxDataEntry[] = useSelector((state: RootState) => {
switch (selectedKey) {
case "+5V":
return state.systemspannung5Vplus[zeitraum] as ReduxDataEntry[];
case "+15V":
return state.systemspannung15Vplus[zeitraum] as ReduxDataEntry[];
case "-15V":
return state.systemspannung15Vminus[zeitraum] as ReduxDataEntry[];
case "-98V":
return state.systemspannung98Vminus[zeitraum] as ReduxDataEntry[];
case "ADC Temp":
return state.temperaturAdWandler[zeitraum] as ReduxDataEntry[];
case "CPU Temp":
return state.temperaturProzessor[zeitraum] as ReduxDataEntry[];
default:
return [] as ReduxDataEntry[];
}
});
const labels = reduxData.map((e: ReduxDataEntry) => e.t);
const values = reduxData.map((e: ReduxDataEntry) => e.i);
const baseOptions = {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: false,
grid: { color: "rgba(200,200,200,0.2)" },
title: { display: true, text: "Wert" },
},
x: {
grid: { color: "rgba(200,200,200,0.2)" },
title: { display: true, text: "Zeit" },
},
},
plugins: {
legend: { position: "bottom" as const },
title: { display: true, text: `Verlauf ${selectedKey}` },
},
};
if (!isOpen || !selectedKey) return null;
return (
<div className="fixed inset-0 bg-black bg-opacity-40 flex items-center justify-center z-50">
<div className="bg-white p-6 rounded-xl w-[50%] h-[60%] overflow-auto shadow-2xl">
<div className="flex justify-between items-center mb-4">
<h2 className="text-xl font-semibold">
Detailansicht: {selectedKey}
</h2>
<button onClick={onClose} className="text-red-500 hover:text-red-700">
</button>
</div>
<div className="flex items-center space-x-2 mb-4">
<label className="font-medium">Zeitraum:</label>
<Listbox value={zeitraum} onChange={setZeitraum}>
<div className="relative w-48">
<Listbox.Button className="w-full border px-3 py-1 rounded text-left bg-white flex justify-between items-center text-sm">
<span>
{
{
DIA0: "Alle Messwerte",
DIA1: "Stündlich",
DIA2: "Täglich",
}[zeitraum]
}
</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">
{["DIA0", "DIA1", "DIA2"].map((option) => (
<Listbox.Option
key={option}
value={option}
className={({ selected, active }) =>
`px-4 py-1 cursor-pointer ${
selected
? "bg-littwin-blue text-white"
: active
? "bg-blue-100"
: ""
}`
}
>
{
{
DIA0: "Alle Messwerte",
DIA1: "Stündlich",
DIA2: "Täglich",
}[option]
}
</Listbox.Option>
))}
</Listbox.Options>
</div>
</Listbox>
</div>
<div className="h-[85%]">
<Line
data={{
labels,
datasets: [
{
label: selectedKey,
data: values,
borderColor: "rgba(59,130,246,1)",
backgroundColor: "rgba(59,130,246,0.2)",
fill: false,
},
],
}}
options={baseOptions}
/>
</div>
</div>
</div>
);
};