"use client"; // components/main/analogInputs/AnalogInputsChart.tsx import React, { useEffect, useRef } from "react"; import { useDispatch, useSelector } from "react-redux"; import { RootState, AppDispatch } from "@/redux/store"; import { Line } from "react-chartjs-2"; import { Chart as ChartJS, LineElement, PointElement, CategoryScale, LinearScale, Tooltip, Legend, Filler, TimeScale, TooltipItem, } from "chart.js"; import "chartjs-adapter-date-fns"; import { de } from "date-fns/locale"; import { getAnalogInputsHistoryThunk } from "@/redux/thunks/getAnalogInputsHistoryThunk"; import { setVonDatum, setBisDatum, setZeitraum, setAutoLoad, } from "@/redux/slices/analogInputs/analogInputsHistorySlice"; import DateRangePicker from "@/components/common/DateRangePicker"; import { Listbox } from "@headlessui/react"; import { getColor } from "@/utils/colors"; ChartJS.register( LineElement, PointElement, CategoryScale, LinearScale, Tooltip, Legend, Filler, TimeScale ); type AnalogInputHistoryPoint = { t: string; m?: number; i?: number; a?: number; g?: number; }; export default function AnalogInputsChart() { useEffect(() => { const loadZoomPlugin = async () => { const zoomPlugin = (await import("chartjs-plugin-zoom")).default; if (!ChartJS.registry.plugins.get("zoom")) { ChartJS.register(zoomPlugin); } }; loadZoomPlugin(); }, []); const dispatch = useDispatch(); const chartRef = useRef(null); const { zeitraum, vonDatum, bisDatum, data, autoLoad, selectedId } = useSelector((state: RootState) => state.analogInputsHistory); const selectedAnalogInput = useSelector( (state: RootState) => state.selectedAnalogInput ); // ✅ Button-Klick → Fetch auslösen const handleFetchData = () => { if (!selectedAnalogInput?.id) return; // Sicherstellen, dass die neuesten Werte aus dem DateRangePicker verwendet werden const latestVonDatum = vonDatum || new Date().toISOString().slice(0, 10); const latestBisDatum = bisDatum || new Date().toISOString().slice(0, 10); dispatch( getAnalogInputsHistoryThunk({ eingang: selectedAnalogInput.id, zeitraum, vonDatum: latestVonDatum, bisDatum: latestBisDatum, }) ); if ( chartRef.current && chartRef.current.options && chartRef.current.options.scales && chartRef.current.options.scales.x ) { const chart = chartRef.current; chart.options.scales.x.min = new Date(latestVonDatum).getTime(); chart.options.scales.x.max = new Date(latestBisDatum).getTime(); // Aktualisiere die Daten des Diagramms const chartKey = selectedAnalogInput?.id ? String(selectedAnalogInput.id + 99) : null; const inputData = chartKey ? data[chartKey] ?? [] : []; const filteredData = inputData.filter((point) => { const date = new Date(point.t); const from = new Date(latestVonDatum); const to = new Date(latestBisDatum); return (!from || date >= from) && (!to || date <= to); }); chart.data.datasets = [ { label: selectedAnalogInput?.label ? `Messwerteingang ${selectedAnalogInput.label}` : "Messwerte", data: filteredData.map((point) => ({ x: new Date(point.t), y: point.m, })), fill: false, borderColor: getColor("littwin-blue"), backgroundColor: "rgba(59,130,246,0.3)", borderWidth: 2, pointRadius: 0, tension: 0.1, }, ]; chart.update("none"); } }; // ✅ Filtere Daten aus Redux const chartKey = selectedAnalogInput?.id ? String(selectedAnalogInput.id + 99) : null; const inputData = chartKey ? data[chartKey] ?? [] : []; // ✅ Zeitbereich anwenden (nur Anzeige gefiltert) const filteredData = inputData.filter((point) => { const date = new Date(point.t); const from = vonDatum ? new Date(vonDatum) : null; const to = bisDatum ? new Date(bisDatum) : null; return (!from || date >= from) && (!to || date <= to); }); useEffect(() => { const today = new Date(); const vor30Tagen = new Date(today); vor30Tagen.setDate(today.getDate() - 30); if (!vonDatum) dispatch(setVonDatum(vor30Tagen.toISOString().slice(0, 10))); if (!bisDatum) dispatch(setBisDatum(today.toISOString().slice(0, 10))); }, [dispatch, vonDatum, bisDatum]); const handleFetchChartData = () => { if (!selectedId) return; dispatch( getAnalogInputsHistoryThunk({ eingang: selectedId, zeitraum, vonDatum, bisDatum, }) ); }; const dataKey = selectedId ? String(selectedId + 99) : null; let filteredPoints: AnalogInputHistoryPoint[] = []; if (dataKey && data[dataKey]) { const fromDate = vonDatum ? new Date(vonDatum) : null; const toDate = bisDatum ? new Date(bisDatum) : null; filteredPoints = data[dataKey].filter((p: AnalogInputHistoryPoint) => { const pointDate = new Date(p.t); return ( (!fromDate || pointDate >= fromDate) && (!toDate || pointDate <= toDate) ); }); } const chartData = { datasets: filteredPoints.length > 0 ? zeitraum === "DIA0" ? [ { label: selectedAnalogInput?.label ? `Messwert (m) ${selectedAnalogInput.label}` : "Messwert (m)", data: filteredData .filter((point) => typeof point.m === "number") .map((point) => ({ x: new Date(point.t), y: point.m })), fill: false, borderColor: getColor("littwin-blue"), backgroundColor: "rgba(59,130,246,0.3)", borderWidth: 2, pointRadius: 0, tension: 0.1, }, { label: "Minimum (i)", data: filteredData .filter((point) => typeof point.i === "number") .map((point) => ({ x: new Date(point.t), y: point.i })), fill: false, borderColor: "gray", // grau borderWidth: 1, pointRadius: 0, borderDash: [4, 2], tension: 0.1, }, { label: "Maximum (a)", data: filteredData .filter((point) => typeof point.a === "number") .map((point) => ({ x: new Date(point.t), y: point.a })), fill: false, borderColor: "gray", // rot borderWidth: 1, pointRadius: 0, borderDash: [4, 2], tension: 0.1, }, ] : [ { label: "Minimum (i)", data: filteredData .filter((point) => typeof point.i === "number") .map((point) => ({ x: new Date(point.t), y: point.i })), fill: false, borderColor: "gray", // grün borderWidth: 1, pointRadius: 0, borderDash: [4, 2], tension: 0.1, }, { label: "Maximum (a)", data: filteredData .filter((point) => typeof point.a === "number") .map((point) => ({ x: new Date(point.t), y: point.a })), fill: false, borderColor: "gray", // rot borderWidth: 1, pointRadius: 0, borderDash: [4, 2], tension: 0.1, }, { label: "Durchschnitt (g)", data: filteredData .filter((point) => typeof point.g === "number") .map((point) => ({ x: new Date(point.t), y: point.g })), fill: false, borderColor: getColor("littwin-blue"), backgroundColor: "rgba(59,130,246,0.3)", borderWidth: 2, pointRadius: 0, tension: 0.1, }, ] : [], }; const chartOptions = { responsive: true, plugins: { legend: { position: "top" as const }, tooltip: { mode: "index" as const, intersect: false, callbacks: { label: function (context: TooltipItem<"line">) { const label = context.dataset.label || ""; return `${label}: ${context.parsed.y}`; }, title: function (tooltipItems: TooltipItem<"line">[]) { const date = tooltipItems[0].parsed.x; return `Zeitpunkt: ${new Date(date).toLocaleString("de-DE")}`; }, }, }, title: { display: true, text: selectedAnalogInput?.label ? `Verlauf: ${selectedAnalogInput.label}` : "Messwert-Verlauf", }, zoom: { pan: { enabled: true, mode: "x" as const }, zoom: { wheel: { enabled: true }, pinch: { enabled: true }, mode: "x" as const, }, }, }, scales: { x: { type: "time" as const, time: { unit: "day" as const, tooltipFormat: "dd.MM.yyyy HH:mm", displayFormats: { day: "dd.MM.yyyy", }, }, adapters: { date: { locale: de } }, title: { display: true, text: "Zeit" }, // ✅ Hier definieren wir den sichtbaren Bereich dynamisch min: vonDatum ? new Date(vonDatum).getTime() : undefined, max: bisDatum ? new Date(bisDatum).getTime() : undefined, }, y: { title: { display: true, text: `Messwert ${selectedAnalogInput?.unit || ""}`, }, }, }, }; // ✅ DateRangePicker Event → Redux-Datum setzen (aber KEIN Fetch!) const handleDateChange = (from: string, to: string) => { dispatch(setVonDatum(from)); dispatch(setBisDatum(to)); }; useEffect(() => { if (autoLoad && selectedId) { dispatch( getAnalogInputsHistoryThunk({ eingang: selectedId, zeitraum, vonDatum, bisDatum, }) ); dispatch(setAutoLoad(false)); // ✅ zurücksetzen, sonst endlose Schleife } }, [autoLoad, selectedId, dispatch, zeitraum, vonDatum, bisDatum]); return (
dispatch(setZeitraum(v))}>
{zeitraum === "DIA0" ? "Alle Messwerte" : zeitraum === "DIA1" ? "Stündlich" : "Täglich"} {["DIA0", "DIA1", "DIA2"].map((option) => ( {option === "DIA0" ? "Alle Messwerte" : option === "DIA1" ? "Stündlich" : "Täglich"} ))}
{!selectedAnalogInput?.id ? (
Bitte wählen Sie einen Eingang aus von der Tabelle, um die Messkurve anzuzeigen
) : ( )}
); }