feature/syasya/testlayout #7
@ -194,7 +194,7 @@ const AdminDashboard = () => {
 | 
			
		||||
 | 
			
		||||
          </div>
 | 
			
		||||
          <div ref={monthlyChartRef} className="pb-5">
 | 
			
		||||
            <MonthlyBarChart siteData={currentSiteDetails} />
 | 
			
		||||
            <MonthlyBarChart siteId={siteIdMap[selectedSite]} />
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import React, { useEffect, useState } from 'react';
 | 
			
		||||
import {
 | 
			
		||||
  BarChart,
 | 
			
		||||
  Bar,
 | 
			
		||||
@ -8,61 +8,106 @@ import {
 | 
			
		||||
  ResponsiveContainer,
 | 
			
		||||
  Legend,
 | 
			
		||||
} from 'recharts';
 | 
			
		||||
import { SiteDetails } from '@/types/SiteData';
 | 
			
		||||
import { format } from 'date-fns';
 | 
			
		||||
import { fetchPowerTimeseries } from '@/app/utils/api';
 | 
			
		||||
 | 
			
		||||
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 generationColor = '#669bbc';
 | 
			
		||||
 | 
			
		||||
// Month names for X-axis labels
 | 
			
		||||
const MONTHS = [
 | 
			
		||||
    'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
 | 
			
		||||
    'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',
 | 
			
		||||
];
 | 
			
		||||
const MonthlyBarChart: React.FC<MonthlyBarChartProps> = ({ siteId }) => {
 | 
			
		||||
  const [chartData, setChartData] = useState<
 | 
			
		||||
    { month: string; consumption: number; generation: number }[]
 | 
			
		||||
  >([]);
 | 
			
		||||
  const [loading, setLoading] = useState(true);
 | 
			
		||||
 | 
			
		||||
const MonthlyBarChart: React.FC<MonthlyBarChartProps> = ({ siteData }) => {
 | 
			
		||||
    const chartData = React.useMemo(() => {
 | 
			
		||||
        if (
 | 
			
		||||
            !siteData ||
 | 
			
		||||
            siteData.consumptionData.length === 0 ||
 | 
			
		||||
            siteData.generationData.length === 0
 | 
			
		||||
        ) {
 | 
			
		||||
            return [];
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (!siteId) return;
 | 
			
		||||
 | 
			
		||||
    const fetchMonthlyData = async () => {
 | 
			
		||||
      setLoading(true);
 | 
			
		||||
      const start = '2025-01-01T00:00:00+08:00';
 | 
			
		||||
      const end = '2025-12-31T23:59:59+08:00';
 | 
			
		||||
 | 
			
		||||
      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
 | 
			
		||||
        const monthlyData = Array.from({ length: 12 }, (_, month) => ({
 | 
			
		||||
            month: MONTHS[month],
 | 
			
		||||
            consumption: 0,
 | 
			
		||||
            generation: 0,
 | 
			
		||||
        for (const entry of groupedGeneration) {
 | 
			
		||||
          if (!monthMap.has(entry.time)) {
 | 
			
		||||
            monthMap.set(entry.time, { consumption: 0, generation: 0 });
 | 
			
		||||
          }
 | 
			
		||||
          monthMap.get(entry.time)!.generation = entry.value;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const formatted = Array.from(monthMap.entries())
 | 
			
		||||
          .sort(([a], [b]) => a.localeCompare(b))
 | 
			
		||||
          .map(([key, val]) => ({
 | 
			
		||||
            month: format(new Date(`${key}-01`), 'MMM'),
 | 
			
		||||
            consumption: val.consumption,
 | 
			
		||||
            generation: val.generation,
 | 
			
		||||
          }));
 | 
			
		||||
 | 
			
		||||
        // 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];
 | 
			
		||||
            }
 | 
			
		||||
        setChartData(formatted.slice(-6)); // last 6 months
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        console.error('Failed to fetch monthly power data:', error);
 | 
			
		||||
        setChartData([]);
 | 
			
		||||
      } finally {
 | 
			
		||||
        setLoading(false);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
        // ✅ Only return the last 6 months
 | 
			
		||||
        return monthlyData.slice(-6);
 | 
			
		||||
    fetchMonthlyData();
 | 
			
		||||
  }, [siteId]);
 | 
			
		||||
 | 
			
		||||
    }, [siteData]);
 | 
			
		||||
 | 
			
		||||
    if (!siteData || chartData.length === 0) {
 | 
			
		||||
  if (loading || !siteId || chartData.length === 0) {
 | 
			
		||||
    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="h-96 w-full flex items-center justify-center">
 | 
			
		||||
                    <p className="text-white/70">No data available for chart. Please select a site.</p>
 | 
			
		||||
          <p className="text-white/70">
 | 
			
		||||
            {loading ? 'Loading data...' : 'No data available for chart.'}
 | 
			
		||||
          </p>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
@ -77,7 +122,7 @@ const MonthlyBarChart: React.FC<MonthlyBarChartProps> = ({ siteData }) => {
 | 
			
		||||
      <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 }}/>
 | 
			
		||||
            <XAxis dataKey="month" tick={{ fontSize: 10 }} />
 | 
			
		||||
            <YAxis tick={{ fontSize: 10 }} />
 | 
			
		||||
            <Tooltip />
 | 
			
		||||
            <Legend />
 | 
			
		||||
@ -91,3 +136,4 @@ const MonthlyBarChart: React.FC<MonthlyBarChartProps> = ({ siteData }) => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default MonthlyBarChart;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user