update monthlybarchart to extract from db

This commit is contained in:
Syasya 2025-07-31 13:59:09 +08:00
parent 5a17af8486
commit 606c1047f6
2 changed files with 117 additions and 71 deletions

View File

@ -194,7 +194,7 @@ const AdminDashboard = () => {
</div> </div>
<div ref={monthlyChartRef} className="pb-5"> <div ref={monthlyChartRef} className="pb-5">
<MonthlyBarChart siteData={currentSiteDetails} /> <MonthlyBarChart siteId={siteIdMap[selectedSite]} />
</div> </div>
</div> </div>

View File

@ -1,93 +1,139 @@
import React from 'react'; import React, { useEffect, useState } from 'react';
import { import {
BarChart, BarChart,
Bar, Bar,
XAxis, XAxis,
YAxis, YAxis,
Tooltip, Tooltip,
ResponsiveContainer, ResponsiveContainer,
Legend, Legend,
} from 'recharts'; } from 'recharts';
import { SiteDetails } from '@/types/SiteData'; import { format } from 'date-fns';
import { fetchPowerTimeseries } from '@/app/utils/api';
interface MonthlyBarChartProps { interface MonthlyBarChartProps {
siteData: SiteDetails | null; siteId: string;
} }
interface TimeSeriesEntry {
time: string;
value: number;
}
const groupTimeSeries = (
data: TimeSeriesEntry[],
mode: 'monthly'
): TimeSeriesEntry[] => {
const groupMap = new Map<string, number[]>();
for (const entry of data) {
const date = new Date(entry.time);
const key = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
if (!groupMap.has(key)) groupMap.set(key, []);
groupMap.get(key)!.push(entry.value);
}
return Array.from(groupMap.entries()).map(([time, values]) => ({
time,
value: values.reduce((sum, v) => sum + v, 0),
}));
};
const consumptionColor = '#003049'; const consumptionColor = '#003049';
const generationColor = '#669bbc'; const generationColor = '#669bbc';
// Month names for X-axis labels const MonthlyBarChart: React.FC<MonthlyBarChartProps> = ({ siteId }) => {
const MONTHS = [ const [chartData, setChartData] = useState<
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', { month: string; consumption: number; generation: number }[]
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', >([]);
]; const [loading, setLoading] = useState(true);
const MonthlyBarChart: React.FC<MonthlyBarChartProps> = ({ siteData }) => { useEffect(() => {
const chartData = React.useMemo(() => { if (!siteId) return;
if (
!siteData || const fetchMonthlyData = async () => {
siteData.consumptionData.length === 0 || setLoading(true);
siteData.generationData.length === 0 const start = '2025-01-01T00:00:00+08:00';
) { const end = '2025-12-31T23:59:59+08:00';
return [];
try {
const res = await fetchPowerTimeseries(siteId, start, end);
const groupedConsumption = groupTimeSeries(res.consumption, 'monthly');
const groupedGeneration = groupTimeSeries(res.generation, 'monthly');
const monthMap = new Map<string, { consumption: number; generation: number }>();
for (const entry of groupedConsumption) {
if (!monthMap.has(entry.time)) {
monthMap.set(entry.time, { consumption: 0, generation: 0 });
}
monthMap.get(entry.time)!.consumption = entry.value;
} }
// Initialize totals for (const entry of groupedGeneration) {
const monthlyData = Array.from({ length: 12 }, (_, month) => ({ if (!monthMap.has(entry.time)) {
month: MONTHS[month], monthMap.set(entry.time, { consumption: 0, generation: 0 });
consumption: 0, }
generation: 0, monthMap.get(entry.time)!.generation = entry.value;
}));
// Group daily data into months (assume data is in order from Jan 1 to Dec 31)
// Group daily data into months (assume data is in order from Jan 1 to Dec 31)
for (let i = 0; i < siteData.consumptionData.length; i++) {
const monthIndex = Math.floor(i / 30.42); // Rough approximation
if (monthIndex < 12) {
monthlyData[monthIndex].consumption += siteData.consumptionData[i];
monthlyData[monthIndex].generation += siteData.generationData[i];
}
} }
// ✅ Only return the last 6 months const formatted = Array.from(monthMap.entries())
return monthlyData.slice(-6); .sort(([a], [b]) => a.localeCompare(b))
.map(([key, val]) => ({
month: format(new Date(`${key}-01`), 'MMM'),
consumption: val.consumption,
generation: val.generation,
}));
}, [siteData]); setChartData(formatted.slice(-6)); // last 6 months
} catch (error) {
console.error('Failed to fetch monthly power data:', error);
setChartData([]);
} finally {
setLoading(false);
}
};
if (!siteData || chartData.length === 0) { fetchMonthlyData();
return ( }, [siteId]);
<div className="bg-white p-4 rounded-lg shadow-md dark:bg-gray-800 dark:text-white-light">
<div className="flex justify-between items-center mb-2">
<h2 className="text-lg font-bold pb-3">Monthly Energy Yield</h2>
</div>
<div className="h-96 w-full flex items-center justify-center">
<p className="text-white/70">No data available for chart. Please select a site.</p>
</div>
</div>
);
}
if (loading || !siteId || chartData.length === 0) {
return ( return (
<div className="bg-white p-4 rounded-lg shadow-md dark:bg-gray-800 dark:text-white-light"> <div className="bg-white p-4 rounded-lg shadow-md dark:bg-gray-800 dark:text-white-light">
<div className="flex justify-between items-center mb-2"> <div className="flex justify-between items-center mb-2">
<h2 className="text-lg font-bold pb-3">Monthly Energy Yield</h2> <h2 className="text-lg font-bold pb-3">Monthly Energy Yield</h2>
</div>
<div className="lg:h-[22.6vw] h-[290px] w-full pt-10">
<ResponsiveContainer width="100%" height="100%">
<BarChart data={chartData}>
<XAxis dataKey="month" tick={{ fontSize: 10 }}/>
<YAxis tick={{ fontSize: 10 }} />
<Tooltip />
<Legend />
<Bar dataKey="consumption" fill={consumptionColor} name="Consumption (kWh)" />
<Bar dataKey="generation" fill={generationColor} name="Generation (kWh)" />
</BarChart>
</ResponsiveContainer>
</div>
</div> </div>
<div className="h-96 w-full flex items-center justify-center">
<p className="text-white/70">
{loading ? 'Loading data...' : 'No data available for chart.'}
</p>
</div>
</div>
); );
}
return (
<div className="bg-white p-4 rounded-lg shadow-md dark:bg-gray-800 dark:text-white-light">
<div className="flex justify-between items-center mb-2">
<h2 className="text-lg font-bold pb-3">Monthly Energy Yield</h2>
</div>
<div className="lg:h-[22.6vw] h-[290px] w-full pt-10">
<ResponsiveContainer width="100%" height="100%">
<BarChart data={chartData}>
<XAxis dataKey="month" tick={{ fontSize: 10 }} />
<YAxis tick={{ fontSize: 10 }} />
<Tooltip />
<Legend />
<Bar dataKey="consumption" fill={consumptionColor} name="Consumption (kWh)" />
<Bar dataKey="generation" fill={generationColor} name="Generation (kWh)" />
</BarChart>
</ResponsiveContainer>
</div>
</div>
);
}; };
export default MonthlyBarChart; export default MonthlyBarChart;