feature/syasya/testlayout #7
@ -1,8 +1,7 @@
 | 
				
			|||||||
// app/adminDashboard/page.tsx
 | 
					 | 
				
			||||||
'use client';
 | 
					'use client';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { useState, useEffect } from 'react';
 | 
					import { useState, useEffect } from 'react';
 | 
				
			||||||
import { useSearchParams } from 'next/navigation';
 | 
					import { useRouter, usePathname, useSearchParams } from 'next/navigation';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import SiteSelector from '@/components/dashboards/SiteSelector';
 | 
					import SiteSelector from '@/components/dashboards/SiteSelector';
 | 
				
			||||||
import SiteStatus from '@/components/dashboards/SiteStatus';
 | 
					import SiteStatus from '@/components/dashboards/SiteStatus';
 | 
				
			||||||
@ -14,97 +13,110 @@ import DashboardLayout from './dashlayout';
 | 
				
			|||||||
import { SiteName, SiteDetails, mockSiteData } from '@/types/SiteData';
 | 
					import { SiteName, SiteDetails, mockSiteData } from '@/types/SiteData';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const AdminDashboard = () => {
 | 
					const AdminDashboard = () => {
 | 
				
			||||||
    const searchParams = useSearchParams();
 | 
					  const router = useRouter();
 | 
				
			||||||
    const siteParam = searchParams?.get('site');
 | 
					  const pathname = usePathname();
 | 
				
			||||||
 | 
					  const searchParams = useSearchParams();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const [selectedSite, setSelectedSite] = useState<SiteName>(() => {
 | 
					  const siteParam = searchParams?.get('site');
 | 
				
			||||||
        const validSiteNames: SiteName[] = ['Site A', 'Site B', 'Site C'];
 | 
					  const validSiteNames: SiteName[] = ['Site A', 'Site B', 'Site C'];
 | 
				
			||||||
        if (siteParam && validSiteNames.includes(siteParam as SiteName)) {
 | 
					 | 
				
			||||||
            return siteParam as SiteName;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return 'Site A';
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    useEffect(() => {
 | 
					  const [selectedSite, setSelectedSite] = useState<SiteName>(() => {
 | 
				
			||||||
        const validSiteNames: SiteName[] = ['Site A', 'Site B', 'Site C'];
 | 
					    if (siteParam && validSiteNames.includes(siteParam as SiteName)) {
 | 
				
			||||||
        if (siteParam && validSiteNames.includes(siteParam as SiteName) && siteParam !== selectedSite) {
 | 
					      return siteParam as SiteName;
 | 
				
			||||||
            setSelectedSite(siteParam as SiteName);
 | 
					    }
 | 
				
			||||||
        }
 | 
					    return 'Site A';
 | 
				
			||||||
    }, [siteParam, selectedSite]);
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const currentSiteDetails: SiteDetails = mockSiteData[selectedSite] || {
 | 
					  // Keep siteParam and selectedSite in sync
 | 
				
			||||||
        location: 'N/A',
 | 
					  useEffect(() => {
 | 
				
			||||||
        inverterProvider: 'N/A',
 | 
					    if (
 | 
				
			||||||
        emergencyContact: 'N/A',
 | 
					      siteParam &&
 | 
				
			||||||
        lastSyncTimestamp: 'N/A',
 | 
					      validSiteNames.includes(siteParam as SiteName) &&
 | 
				
			||||||
        consumptionData: [],
 | 
					      siteParam !== selectedSite
 | 
				
			||||||
        generationData: [],
 | 
					    ) {
 | 
				
			||||||
        systemStatus: 'N/A', // Fallback
 | 
					      setSelectedSite(siteParam as SiteName);
 | 
				
			||||||
        temperature: 'N/A', // Fallback
 | 
					    }
 | 
				
			||||||
        solarPower: 0, // Fallback
 | 
					  }, [siteParam, selectedSite]);
 | 
				
			||||||
        realTimePower: 0, // Fallback
 | 
					 | 
				
			||||||
        installedPower: 0, // Fallback
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const handleCSVExport = () => {
 | 
					  // Update query string when site is changed manually
 | 
				
			||||||
        alert('Exported raw data to CSV (mock)');
 | 
					  const handleSiteChange = (newSite: SiteName) => {
 | 
				
			||||||
    };
 | 
					    setSelectedSite(newSite);
 | 
				
			||||||
 | 
					    const newUrl = `${pathname}?site=${encodeURIComponent(newSite)}`;
 | 
				
			||||||
 | 
					    router.push(newUrl);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const handlePDFExport = () => {
 | 
					  const currentSiteDetails: SiteDetails = mockSiteData[selectedSite] || {
 | 
				
			||||||
        alert('Exported chart images to PDF (mock)');
 | 
					    location: 'N/A',
 | 
				
			||||||
    };
 | 
					    inverterProvider: 'N/A',
 | 
				
			||||||
 | 
					    emergencyContact: 'N/A',
 | 
				
			||||||
 | 
					    lastSyncTimestamp: 'N/A',
 | 
				
			||||||
 | 
					    consumptionData: [],
 | 
				
			||||||
 | 
					    generationData: [],
 | 
				
			||||||
 | 
					    systemStatus: 'N/A',
 | 
				
			||||||
 | 
					    temperature: 'N/A',
 | 
				
			||||||
 | 
					    solarPower: 0,
 | 
				
			||||||
 | 
					    realTimePower: 0,
 | 
				
			||||||
 | 
					    installedPower: 0,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					  const handleCSVExport = () => {
 | 
				
			||||||
         <DashboardLayout>
 | 
					    alert('Exported raw data to CSV (mock)');
 | 
				
			||||||
            <div className="px-6 space-y-6">
 | 
					  };
 | 
				
			||||||
                <h1 className='text-lg font-semibold'>Admin Dashboard</h1>
 | 
					 | 
				
			||||||
                {/* Top Section: Site Selector, Site Status, and KPI Table */}
 | 
					 | 
				
			||||||
                {/* This grid will now properly arrange them into two columns on md screens and up */}
 | 
					 | 
				
			||||||
                <div className="grid md:grid-cols-2 gap-6">
 | 
					 | 
				
			||||||
                    {/* First Column: Site Selector and Site Status */}
 | 
					 | 
				
			||||||
                    <div className="space-y-4">
 | 
					 | 
				
			||||||
                        <SiteSelector selectedSite={selectedSite} setSelectedSite={setSelectedSite} />
 | 
					 | 
				
			||||||
                        <SiteStatus
 | 
					 | 
				
			||||||
                            selectedSite={selectedSite}
 | 
					 | 
				
			||||||
                            location={currentSiteDetails.location}
 | 
					 | 
				
			||||||
                            inverterProvider={currentSiteDetails.inverterProvider}
 | 
					 | 
				
			||||||
                            emergencyContact={currentSiteDetails.emergencyContact}
 | 
					 | 
				
			||||||
                            lastSyncTimestamp={currentSiteDetails.lastSyncTimestamp}
 | 
					 | 
				
			||||||
                        />
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                    {/* Second Column: KPI Table */}
 | 
					 | 
				
			||||||
                    <div> {/* This div will now be the second column */}
 | 
					 | 
				
			||||||
                        <KPI_Table siteData={currentSiteDetails} />
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handlePDFExport = () => {
 | 
				
			||||||
 | 
					    alert('Exported chart images to PDF (mock)');
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <DashboardLayout>
 | 
				
			||||||
 | 
					      <div className="px-6 space-y-6">
 | 
				
			||||||
 | 
					        <h1 className="text-lg font-semibold">Admin Dashboard</h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                {/* Charts Section */}
 | 
					        <div className="grid md:grid-cols-2 gap-6">
 | 
				
			||||||
                <div className="grid md:grid-cols-2 gap-6">
 | 
					          <div className="space-y-4">
 | 
				
			||||||
                    <div className="pb-5">
 | 
					            <SiteSelector
 | 
				
			||||||
                        <EnergyLineChart
 | 
					              selectedSite={selectedSite}
 | 
				
			||||||
                            consumptionData={currentSiteDetails.consumptionData}
 | 
					              setSelectedSite={handleSiteChange}
 | 
				
			||||||
                            generationData={currentSiteDetails.generationData}
 | 
					            />
 | 
				
			||||||
                        />
 | 
					            <SiteStatus
 | 
				
			||||||
                    </div>
 | 
					              selectedSite={selectedSite}
 | 
				
			||||||
                    <div className="pb-5">
 | 
					              location={currentSiteDetails.location}
 | 
				
			||||||
                        <MonthlyBarChart siteData={currentSiteDetails} />
 | 
					              inverterProvider={currentSiteDetails.inverterProvider}
 | 
				
			||||||
                    </div>
 | 
					              emergencyContact={currentSiteDetails.emergencyContact}
 | 
				
			||||||
                </div>
 | 
					              lastSyncTimestamp={currentSiteDetails.lastSyncTimestamp}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <div className="flex flex-col md:flex-row gap-4 justify-center"> {/* Added a div wrapper */}
 | 
					          <div>
 | 
				
			||||||
                    <button onClick={handleCSVExport} className="text-sm lg:text-lg btn-primary">
 | 
					            <KPI_Table siteData={currentSiteDetails} />
 | 
				
			||||||
                        Export Raw Data to CSV
 | 
					          </div>
 | 
				
			||||||
                    </button>
 | 
					        </div>
 | 
				
			||||||
                    <button onClick={handlePDFExport} className="text-sm lg:text-lg btn-primary">
 | 
					
 | 
				
			||||||
                        Export Chart Images to PDF
 | 
					        <div className="grid md:grid-cols-2 gap-6">
 | 
				
			||||||
                    </button>
 | 
					          <div className="pb-5">
 | 
				
			||||||
                </div>
 | 
					            <EnergyLineChart
 | 
				
			||||||
            </div>
 | 
					              consumptionData={currentSiteDetails.consumptionData}
 | 
				
			||||||
        </DashboardLayout>
 | 
					              generationData={currentSiteDetails.generationData}
 | 
				
			||||||
    );
 | 
					            />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div className="pb-5">
 | 
				
			||||||
 | 
					            <MonthlyBarChart siteData={currentSiteDetails} />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div className="flex flex-col md:flex-row gap-4 justify-center">
 | 
				
			||||||
 | 
					          <button onClick={handleCSVExport} className="text-sm lg:text-lg btn-primary">
 | 
				
			||||||
 | 
					            Export Raw Data to CSV
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button onClick={handlePDFExport} className="text-sm lg:text-lg btn-primary">
 | 
				
			||||||
 | 
					            Export Chart Images to PDF
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </DashboardLayout>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default AdminDashboard;
 | 
					export default AdminDashboard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -12,7 +12,7 @@ const LoginPage = (props: Props) => {
 | 
				
			|||||||
                <img src="/assets/images/auth/bg-gradient.png" alt="image" className="h-full w-full object-cover" />
 | 
					                <img src="/assets/images/auth/bg-gradient.png" alt="image" className="h-full w-full object-cover" />
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <div className="relative flex min-h-screen items-center justify-center bg-[url(/assets/images/auth/map.png)] bg-cover bg-center bg-no-repeat px-6 py-10 dark:bg-[#060818] sm:px-16">
 | 
					            <div className="relative flex min-h-screen items-center justify-center bg-[linear-gradient(45deg,#ffffff_0%,#fcd913_100%)] bg-cover bg-center bg-no-repeat px-6 py-10 dark:bg-[#060818] sm:px-16">
 | 
				
			||||||
                <img src="/assets/images/auth/coming-soon-object1.png" alt="image" className="absolute left-0 top-1/2 h-full max-h-[893px] -translate-y-1/2" />
 | 
					                <img src="/assets/images/auth/coming-soon-object1.png" alt="image" className="absolute left-0 top-1/2 h-full max-h-[893px] -translate-y-1/2" />
 | 
				
			||||||
                <img src="/assets/images/auth/coming-soon-object2.png" alt="image" className="absolute left-24 top-0 h-40 md:left-[30%]" />
 | 
					                <img src="/assets/images/auth/coming-soon-object2.png" alt="image" className="absolute left-24 top-0 h-40 md:left-[30%]" />
 | 
				
			||||||
                <img src="/assets/images/auth/coming-soon-object3.png" alt="image" className="absolute right-0 top-0 h-[300px]" />
 | 
					                <img src="/assets/images/auth/coming-soon-object3.png" alt="image" className="absolute right-0 top-0 h-[300px]" />
 | 
				
			||||||
 | 
				
			|||||||
@ -12,7 +12,7 @@ const RegisterPage = (props: Props) => {
 | 
				
			|||||||
                <img src="/assets/images/auth/bg-gradient.png" alt="image" className="h-full w-full object-cover" />
 | 
					                <img src="/assets/images/auth/bg-gradient.png" alt="image" className="h-full w-full object-cover" />
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <div className="relative flex min-h-screen items-center justify-center bg-[url(/assets/images/auth/map.png)] bg-cover bg-center bg-no-repeat px-6 py-10 dark:bg-[#060818] sm:px-16">
 | 
					            <div className="relative flex min-h-screen items-center justify-center bg-[linear-gradient(45deg,#ffffff_0%,#fcd913_100%)] bg-cover bg-center bg-no-repeat px-6 py-10 dark:bg-[#060818] sm:px-16">
 | 
				
			||||||
                <img src="/assets/images/auth/coming-soon-object1.png" alt="image" className="absolute left-0 top-1/2 h-full max-h-[893px] -translate-y-1/2" />
 | 
					                <img src="/assets/images/auth/coming-soon-object1.png" alt="image" className="absolute left-0 top-1/2 h-full max-h-[893px] -translate-y-1/2" />
 | 
				
			||||||
                <img src="/assets/images/auth/coming-soon-object2.png" alt="image" className="absolute left-24 top-0 h-40 md:left-[30%]" />
 | 
					                <img src="/assets/images/auth/coming-soon-object2.png" alt="image" className="absolute left-24 top-0 h-40 md:left-[30%]" />
 | 
				
			||||||
                <img src="/assets/images/auth/coming-soon-object3.png" alt="image" className="absolute right-0 top-0 h-[300px]" />
 | 
					                <img src="/assets/images/auth/coming-soon-object3.png" alt="image" className="absolute right-0 top-0 h-[300px]" />
 | 
				
			||||||
 | 
				
			|||||||
@ -1,16 +1,22 @@
 | 
				
			|||||||
'use client'
 | 
					'use client';
 | 
				
			||||||
import { Metadata } from 'next';
 | 
					 | 
				
			||||||
import React, { useState } from 'react';
 | 
					import React, { useState } from 'react';
 | 
				
			||||||
 | 
					import { useRouter } from 'next/navigation';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Sales = () => {
 | 
					const Sales = () => {
 | 
				
			||||||
  const [selectedSite, setSelectedSite] = useState('');
 | 
					  const [selectedSite, setSelectedSite] = useState('');
 | 
				
			||||||
  const sites = ['Site A', 'Site B', 'Site C']; // replace with your actual site list
 | 
					  const sites = ['Site A', 'Site B', 'Site C'];
 | 
				
			||||||
 | 
					  const router = useRouter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleGoToDashboard = () => {
 | 
				
			||||||
 | 
					  if (selectedSite) {
 | 
				
			||||||
 | 
					    router.push(`/adminDashboard?site=${encodeURIComponent(selectedSite)}`);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className="min-h-screen flex flex-col items-center justify-center p-4 bg-gray-50">
 | 
					    <div className="min-h-screen flex flex-col items-center justify-center p-4 bg-gray-50">
 | 
				
			||||||
      <h1 className="text-3xl font-bold mb-4 text-gray-800">
 | 
					      <h1 className="text-3xl font-bold mb-4 text-gray-800">
 | 
				
			||||||
        Welcome to Rooftop Dashboard !
 | 
					        Welcome to Rooftop Dashboard!
 | 
				
			||||||
      </h1>
 | 
					      </h1>
 | 
				
			||||||
      <h2 className="text-2xl font-bold mb-4 text-gray-800">
 | 
					      <h2 className="text-2xl font-bold mb-4 text-gray-800">
 | 
				
			||||||
        Select a site to get started.
 | 
					        Select a site to get started.
 | 
				
			||||||
@ -31,12 +37,17 @@ const Sales = () => {
 | 
				
			|||||||
            </option>
 | 
					            </option>
 | 
				
			||||||
          ))}
 | 
					          ))}
 | 
				
			||||||
        </select>
 | 
					        </select>
 | 
				
			||||||
        {selectedSite && (
 | 
					 | 
				
			||||||
            <div className="flex flex-col space-y-2">
 | 
					 | 
				
			||||||
                <p className="mt-4 text-green-700">You selected: {selectedSite}</p>
 | 
					 | 
				
			||||||
                <button className="btn-primary">Go to Dashboard</button>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        {selectedSite && (
 | 
				
			||||||
 | 
					          <div className="flex flex-col space-y-2">
 | 
				
			||||||
 | 
					            <p className="mt-4 text-green-700">You selected: {selectedSite}</p>
 | 
				
			||||||
 | 
					            <button
 | 
				
			||||||
 | 
					              onClick={handleGoToDashboard}
 | 
				
			||||||
 | 
					              className="bg-yellow-400 hover:bg-yellow-500 text-white font-semibold py-2 px-4 rounded"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              Go to Dashboard
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
@ -45,3 +56,4 @@ const Sales = () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export default Sales;
 | 
					export default Sales;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,34 +1,13 @@
 | 
				
			|||||||
// components/dashboards/EnergyLineChart.tsx
 | 
					import React, { useRef, useEffect, useState } from 'react';
 | 
				
			||||||
'use client';
 | 
					 | 
				
			||||||
import { useRef, useEffect } from 'react';
 | 
					 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  Chart as ChartJS,
 | 
					 | 
				
			||||||
  LineElement,
 | 
					 | 
				
			||||||
  PointElement,
 | 
					 | 
				
			||||||
  LinearScale,
 | 
					 | 
				
			||||||
  CategoryScale,
 | 
					 | 
				
			||||||
  Title,
 | 
					 | 
				
			||||||
  Tooltip,
 | 
					 | 
				
			||||||
  Legend,
 | 
					 | 
				
			||||||
} from 'chart.js';
 | 
					 | 
				
			||||||
import zoomPlugin from 'chartjs-plugin-zoom';
 | 
					 | 
				
			||||||
import { Line } from 'react-chartjs-2';
 | 
					import { Line } from 'react-chartjs-2';
 | 
				
			||||||
 | 
					import ChartJS from 'chart.js/auto';
 | 
				
			||||||
 | 
					import zoomPlugin from 'chartjs-plugin-zoom';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ChartJS.register(
 | 
					ChartJS.register(zoomPlugin);
 | 
				
			||||||
  LineElement,
 | 
					 | 
				
			||||||
  PointElement,
 | 
					 | 
				
			||||||
  LinearScale,
 | 
					 | 
				
			||||||
  CategoryScale,
 | 
					 | 
				
			||||||
  Title,
 | 
					 | 
				
			||||||
  Tooltip,
 | 
					 | 
				
			||||||
  Legend,
 | 
					 | 
				
			||||||
  zoomPlugin
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Define props interface for EnergyLineChart
 | 
					 | 
				
			||||||
interface EnergyLineChartProps {
 | 
					interface EnergyLineChartProps {
 | 
				
			||||||
    consumptionData: number[];
 | 
					  consumptionData: number[];
 | 
				
			||||||
    generationData: number[];
 | 
					  generationData: number[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const labels = [
 | 
					const labels = [
 | 
				
			||||||
@ -40,30 +19,38 @@ const labels = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const EnergyLineChart = ({ consumptionData, generationData }: EnergyLineChartProps) => {
 | 
					const EnergyLineChart = ({ consumptionData, generationData }: EnergyLineChartProps) => {
 | 
				
			||||||
  const chartRef = useRef<any>(null);
 | 
					  const chartRef = useRef<any>(null);
 | 
				
			||||||
    useEffect(() => {
 | 
					
 | 
				
			||||||
 | 
					  const [startIndex, setStartIndex] = useState(0);
 | 
				
			||||||
 | 
					  const [endIndex, setEndIndex] = useState(labels.length - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
    if (typeof window !== 'undefined') {
 | 
					    if (typeof window !== 'undefined') {
 | 
				
			||||||
      import('hammerjs');
 | 
					      import('hammerjs');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }, []);
 | 
					  }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Calculate suggestedMax dynamically based on the current data
 | 
					  // Filter data arrays based on selected range
 | 
				
			||||||
  const allDataPoints = [...consumptionData, ...generationData];
 | 
					  const filteredConsumption = consumptionData.slice(startIndex, endIndex + 1);
 | 
				
			||||||
  const maxDataValue = allDataPoints.length > 0 ? Math.max(...allDataPoints) : 0; // Handle empty array
 | 
					  const filteredGeneration = generationData.slice(startIndex, endIndex + 1);
 | 
				
			||||||
  const yAxisSuggestedMax = maxDataValue * 1.15; // Adds 15% padding
 | 
					  const filteredLabels = labels.slice(startIndex, endIndex + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const allDataPoints = [...filteredConsumption, ...filteredGeneration];
 | 
				
			||||||
 | 
					  const maxDataValue = allDataPoints.length > 0 ? Math.max(...allDataPoints) : 0;
 | 
				
			||||||
 | 
					  const yAxisSuggestedMax = maxDataValue * 1.15;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const data = {
 | 
					  const data = {
 | 
				
			||||||
    labels,
 | 
					    labels: filteredLabels,
 | 
				
			||||||
    datasets: [
 | 
					    datasets: [
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        label: 'Consumption',
 | 
					        label: 'Consumption',
 | 
				
			||||||
        data: consumptionData, // Use prop data
 | 
					        data: filteredConsumption,
 | 
				
			||||||
        borderColor: '#8884d8',
 | 
					        borderColor: '#8884d8',
 | 
				
			||||||
        tension: 0.4,
 | 
					        tension: 0.4,
 | 
				
			||||||
        fill: false,
 | 
					        fill: false,
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        label: 'Generation',
 | 
					        label: 'Generation',
 | 
				
			||||||
        data: generationData, // Use prop data
 | 
					        data: filteredGeneration,
 | 
				
			||||||
        borderColor: '#82ca9d',
 | 
					        borderColor: '#82ca9d',
 | 
				
			||||||
        tension: 0.4,
 | 
					        tension: 0.4,
 | 
				
			||||||
        fill: false,
 | 
					        fill: false,
 | 
				
			||||||
@ -75,35 +62,19 @@ const EnergyLineChart = ({ consumptionData, generationData }: EnergyLineChartPro
 | 
				
			|||||||
    responsive: true,
 | 
					    responsive: true,
 | 
				
			||||||
    maintainAspectRatio: false,
 | 
					    maintainAspectRatio: false,
 | 
				
			||||||
    plugins: {
 | 
					    plugins: {
 | 
				
			||||||
      legend: {
 | 
					      legend: { position: 'top' as const },
 | 
				
			||||||
        position: 'top' as const,
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      zoom: {
 | 
					      zoom: {
 | 
				
			||||||
        zoom: {
 | 
					        zoom: {
 | 
				
			||||||
          wheel: {
 | 
					          wheel: { enabled: true },
 | 
				
			||||||
            enabled: true,
 | 
					          pinch: { enabled: true },
 | 
				
			||||||
          },
 | 
					          mode: 'x' as const,
 | 
				
			||||||
          pinch: {
 | 
					 | 
				
			||||||
            enabled: true,
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
          mode: "x" as const,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        pan: {
 | 
					 | 
				
			||||||
          enabled: true,
 | 
					 | 
				
			||||||
          mode: "x" as const,
 | 
					 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        pan: { enabled: true, mode: 'x' as const },
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      tooltip: {
 | 
					      tooltip: { enabled: true, mode: 'index' as const, intersect: false },
 | 
				
			||||||
        enabled: true,
 | 
					 | 
				
			||||||
        mode: 'index' as const,
 | 
					 | 
				
			||||||
        intersect: false,
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    scales: {
 | 
					    scales: {
 | 
				
			||||||
      y: {
 | 
					      y: { beginAtZero: true, suggestedMax: yAxisSuggestedMax },
 | 
				
			||||||
        beginAtZero: true,
 | 
					 | 
				
			||||||
        suggestedMax: yAxisSuggestedMax, // Use the dynamically calculated value
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -116,13 +87,49 @@ const EnergyLineChart = ({ consumptionData, generationData }: EnergyLineChartPro
 | 
				
			|||||||
      <div className="h-98 w-full">
 | 
					      <div className="h-98 w-full">
 | 
				
			||||||
        <div className="flex justify-between items-center mb-2">
 | 
					        <div className="flex justify-between items-center mb-2">
 | 
				
			||||||
          <h2 className="text-lg font-bold dark:text-white-light">Energy Consumption & Generation</h2>
 | 
					          <h2 className="text-lg font-bold dark:text-white-light">Energy Consumption & Generation</h2>
 | 
				
			||||||
          <button
 | 
					          <button onClick={handleResetZoom} className="btn-primary px-8 py-2 text-sm">
 | 
				
			||||||
            onClick={handleResetZoom}
 | 
					 | 
				
			||||||
            className="btn-primary px-8 py-2 text-sm"
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            Reset
 | 
					            Reset
 | 
				
			||||||
          </button>
 | 
					          </button>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        {/* Time range selectors */}
 | 
				
			||||||
 | 
					        <div className="mb-4 flex gap-4 items-center">
 | 
				
			||||||
 | 
					          <label className='font-medium'>
 | 
				
			||||||
 | 
					            From:{' '}
 | 
				
			||||||
 | 
					            <select
 | 
				
			||||||
 | 
					              value={startIndex}
 | 
				
			||||||
 | 
					              onChange={(e) => {
 | 
				
			||||||
 | 
					                const val = Number(e.target.value);
 | 
				
			||||||
 | 
					                setStartIndex(val <= endIndex ? val : endIndex);
 | 
				
			||||||
 | 
					              }}
 | 
				
			||||||
 | 
					              className="border rounded p-1"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              {labels.map((label, idx) => (
 | 
				
			||||||
 | 
					                <option key={idx} value={idx}>
 | 
				
			||||||
 | 
					                  {label}
 | 
				
			||||||
 | 
					                </option>
 | 
				
			||||||
 | 
					              ))}
 | 
				
			||||||
 | 
					            </select>
 | 
				
			||||||
 | 
					          </label>
 | 
				
			||||||
 | 
					          <label className='font-medium'>
 | 
				
			||||||
 | 
					            To:{' '}
 | 
				
			||||||
 | 
					            <select
 | 
				
			||||||
 | 
					              value={endIndex}
 | 
				
			||||||
 | 
					              onChange={(e) => {
 | 
				
			||||||
 | 
					                const val = Number(e.target.value);
 | 
				
			||||||
 | 
					                setEndIndex(val >= startIndex ? val : startIndex);
 | 
				
			||||||
 | 
					              }}
 | 
				
			||||||
 | 
					              className="border rounded p-1"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              {labels.map((label, idx) => (
 | 
				
			||||||
 | 
					                <option key={idx} value={idx}>
 | 
				
			||||||
 | 
					                  {label}
 | 
				
			||||||
 | 
					                </option>
 | 
				
			||||||
 | 
					              ))}
 | 
				
			||||||
 | 
					            </select>
 | 
				
			||||||
 | 
					          </label>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className="h-96 w-full">
 | 
					        <div className="h-96 w-full">
 | 
				
			||||||
          <Line ref={chartRef} data={data} options={options} />
 | 
					          <Line ref={chartRef} data={data} options={options} />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
@ -133,3 +140,4 @@ const EnergyLineChart = ({ consumptionData, generationData }: EnergyLineChartPro
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export default EnergyLineChart;
 | 
					export default EnergyLineChart;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,3 @@
 | 
				
			|||||||
// components/MonthlyBarChart.tsx
 | 
					 | 
				
			||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    BarChart,
 | 
					    BarChart,
 | 
				
			||||||
@ -7,42 +6,57 @@ import {
 | 
				
			|||||||
    YAxis,
 | 
					    YAxis,
 | 
				
			||||||
    Tooltip,
 | 
					    Tooltip,
 | 
				
			||||||
    ResponsiveContainer,
 | 
					    ResponsiveContainer,
 | 
				
			||||||
    Cell,
 | 
					    Legend,
 | 
				
			||||||
    Legend // Import Legend to distinguish between consumption and generation
 | 
					 | 
				
			||||||
} from 'recharts';
 | 
					} from 'recharts';
 | 
				
			||||||
import { SiteDetails } from '@/types/SiteData'; // Adjust import path as necessary
 | 
					import { SiteDetails } from '@/types/SiteData';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface MonthlyBarChartProps {
 | 
					interface MonthlyBarChartProps {
 | 
				
			||||||
    siteData: SiteDetails | null; // Pass the selected site's data as a prop
 | 
					    siteData: SiteDetails | null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Define specific colors for consumption and generation
 | 
					const consumptionColor = '#003049';
 | 
				
			||||||
const consumptionColor = '#003049'; // Darker blue/grey for consumption
 | 
					const generationColor = '#669bbc';
 | 
				
			||||||
const generationColor = '#669bbc'; // Lighter blue for generation
 | 
					
 | 
				
			||||||
 | 
					// 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> = ({ siteData }) => {
 | 
					const MonthlyBarChart: React.FC<MonthlyBarChartProps> = ({ siteData }) => {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Prepare data for the chart
 | 
					 | 
				
			||||||
    const chartData = React.useMemo(() => {
 | 
					    const chartData = React.useMemo(() => {
 | 
				
			||||||
        if (!siteData || siteData.consumptionData.length === 0 || siteData.generationData.length === 0) {
 | 
					        if (
 | 
				
			||||||
 | 
					            !siteData ||
 | 
				
			||||||
 | 
					            siteData.consumptionData.length === 0 ||
 | 
				
			||||||
 | 
					            siteData.generationData.length === 0
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
            return [];
 | 
					            return [];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Assuming consumptionData and generationData are arrays of daily values
 | 
					        // Initialize totals
 | 
				
			||||||
        // We'll map them to an array suitable for Recharts
 | 
					        const monthlyData = Array.from({ length: 12 }, (_, month) => ({
 | 
				
			||||||
        const dataLength = Math.min(siteData.consumptionData.length, siteData.generationData.length);
 | 
					            month: MONTHS[month],
 | 
				
			||||||
        return Array.from({ length: dataLength }).map((_, index) => ({
 | 
					            consumption: 0,
 | 
				
			||||||
            day: `Day ${index + 1}`, // Label for X-axis
 | 
					            generation: 0,
 | 
				
			||||||
            consumption: siteData.consumptionData[index],
 | 
					 | 
				
			||||||
            generation: siteData.generationData[index],
 | 
					 | 
				
			||||||
        }));
 | 
					        }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 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 (or replace with actual dates if available)
 | 
				
			||||||
 | 
					            if (monthIndex < 12) {
 | 
				
			||||||
 | 
					                monthlyData[monthIndex].consumption += siteData.consumptionData[i];
 | 
				
			||||||
 | 
					                monthlyData[monthIndex].generation += siteData.generationData[i];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return monthlyData;
 | 
				
			||||||
    }, [siteData]);
 | 
					    }, [siteData]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!siteData || chartData.length === 0) {
 | 
					    if (!siteData || 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">Daily Energy Consumption & Generation</h2>
 | 
					                    <h2 className="text-lg font-bold pb-3">Monthly Energy Yield</h2>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div className="h-96 w-full flex items-center justify-center">
 | 
					                <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">No data available for chart. Please select a site.</p>
 | 
				
			||||||
@ -53,31 +67,19 @@ const MonthlyBarChart: React.FC<MonthlyBarChartProps> = ({ siteData }) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    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">
 | 
				
			||||||
            {/* Chart Title and any other header elements */}
 | 
					 | 
				
			||||||
            <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">Daily Energy Consumption & Generation</h2>
 | 
					                <h2 className="text-lg font-bold pb-3">Monthly Energy Yield</h2>
 | 
				
			||||||
                {/* You could add buttons or other controls here if needed */}
 | 
					 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            {/* This div now acts as the direct container for the chart */}
 | 
					 | 
				
			||||||
            {/* It explicitly sets the height and width for the ResponsiveContainer */}
 | 
					 | 
				
			||||||
            <div className="h-96 w-full">
 | 
					            <div className="h-96 w-full">
 | 
				
			||||||
                <ResponsiveContainer width="100%" height="100%">
 | 
					                <ResponsiveContainer width="100%" height="100%">
 | 
				
			||||||
                    <BarChart data={chartData}>
 | 
					                    <BarChart data={chartData}>
 | 
				
			||||||
                        <XAxis dataKey="day" interval={chartData.length > 10 ? 'preserveStartEnd' : 0} /> {/* Adjust interval for readability */}
 | 
					                        <XAxis dataKey="month" />
 | 
				
			||||||
                        <YAxis />
 | 
					                        <YAxis />
 | 
				
			||||||
                        <Tooltip />
 | 
					                        <Tooltip />
 | 
				
			||||||
                        <Legend /> {/* Add Legend for consumption and generation bars */}
 | 
					                        <Legend />
 | 
				
			||||||
 | 
					                        <Bar dataKey="consumption" fill={consumptionColor} name="Consumption (kWh)" />
 | 
				
			||||||
                        {/* Bar for Consumption */}
 | 
					                        <Bar dataKey="generation" fill={generationColor} name="Generation (kWh)" />
 | 
				
			||||||
                        <Bar dataKey="consumption" fill={consumptionColor} name="Consumption (kWh)">
 | 
					 | 
				
			||||||
                            {/* You can still apply individual cell colors if needed, but a single fill is often clearer for categories */}
 | 
					 | 
				
			||||||
                        </Bar>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        {/* Bar for Generation */}
 | 
					 | 
				
			||||||
                        <Bar dataKey="generation" fill={generationColor} name="Generation (kWh)">
 | 
					 | 
				
			||||||
                            {/* You can still apply individual cell colors if needed */}
 | 
					 | 
				
			||||||
                        </Bar>
 | 
					 | 
				
			||||||
                    </BarChart>
 | 
					                    </BarChart>
 | 
				
			||||||
                </ResponsiveContainer>
 | 
					                </ResponsiveContainer>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
@ -85,4 +87,4 @@ const MonthlyBarChart: React.FC<MonthlyBarChartProps> = ({ siteData }) => {
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default MonthlyBarChart;
 | 
					export default MonthlyBarChart;
 | 
				
			||||||
 | 
				
			|||||||
@ -34,6 +34,11 @@ const calculateMonthlyTotal = (dataArray: number[]): number => {
 | 
				
			|||||||
    return dataArray.reduce((sum, value) => sum + value, 0);
 | 
					    return dataArray.reduce((sum, value) => sum + value, 0);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const generateYearlyDataInRange = (min: number, max: number) =>
 | 
				
			||||||
 | 
					  Array(365)
 | 
				
			||||||
 | 
					    .fill(0)
 | 
				
			||||||
 | 
					    .map(() => Math.floor(Math.random() * (max - min + 1)) + min);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const mockSiteData: Record<SiteName, SiteDetails> = {
 | 
					export const mockSiteData: Record<SiteName, SiteDetails> = {
 | 
				
			||||||
    'Site A': {
 | 
					    'Site A': {
 | 
				
			||||||
@ -41,8 +46,8 @@ export const mockSiteData: Record<SiteName, SiteDetails> = {
 | 
				
			|||||||
        inverterProvider: 'SolarEdge',
 | 
					        inverterProvider: 'SolarEdge',
 | 
				
			||||||
        emergencyContact: '+60 12-345 6789',
 | 
					        emergencyContact: '+60 12-345 6789',
 | 
				
			||||||
        lastSyncTimestamp: '2025-06-03 15:30:00',
 | 
					        lastSyncTimestamp: '2025-06-03 15:30:00',
 | 
				
			||||||
        consumptionData: [100, 110, 120, 130, 125, 140, 135, 120, 110, 180, 100, 130, 90, 150, 160, 170, 180, 175, 160], // Example daily kWh for 19 days
 | 
					        consumptionData: generateYearlyDataInRange(80, 250),
 | 
				
			||||||
        generationData: [80, 90, 95, 105, 110, 120, 115, 150, 130, 160, 120, 140, 120, 140, 130, 140, 150, 155, 140], // Example daily kWh for 19 days
 | 
					        generationData: generateYearlyDataInRange(80, 250),
 | 
				
			||||||
        systemStatus: 'Normal',
 | 
					        systemStatus: 'Normal',
 | 
				
			||||||
        temperature: '35°C',
 | 
					        temperature: '35°C',
 | 
				
			||||||
        solarPower: 108.4,
 | 
					        solarPower: 108.4,
 | 
				
			||||||
@ -50,15 +55,15 @@ export const mockSiteData: Record<SiteName, SiteDetails> = {
 | 
				
			|||||||
        installedPower: 174.9, // kWp
 | 
					        installedPower: 174.9, // kWp
 | 
				
			||||||
        gridImportPrice_RM_per_kWh: 0.50, // Example: RM 0.50 per kWh
 | 
					        gridImportPrice_RM_per_kWh: 0.50, // Example: RM 0.50 per kWh
 | 
				
			||||||
        solarExportTariff_RM_per_kWh: 0.30, // Example: RM 0.30 per kWh
 | 
					        solarExportTariff_RM_per_kWh: 0.30, // Example: RM 0.30 per kWh
 | 
				
			||||||
        theoreticalMaxGeneration_kWh: 25000, // Example: Theoretical max for 174.9 kWp over a month in Malaysia
 | 
					        theoreticalMaxGeneration_kWh: 80000, // Example: Theoretical max for 174.9 kWp over a month in Malaysia
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    'Site B': {
 | 
					    'Site B': {
 | 
				
			||||||
        location: 'Kuala Lumpur, Wilayah Persekutuan',
 | 
					        location: 'Kuala Lumpur, Wilayah Persekutuan',
 | 
				
			||||||
        inverterProvider: 'Huawei',
 | 
					        inverterProvider: 'Huawei',
 | 
				
			||||||
        emergencyContact: '+60 19-876 5432',
 | 
					        emergencyContact: '+60 19-876 5432',
 | 
				
			||||||
        lastSyncTimestamp: '2025-06-02 10:15:00',
 | 
					        lastSyncTimestamp: '2025-06-02 10:15:00',
 | 
				
			||||||
        consumptionData: [90, 100, 110, 120, 115, 130, 125, 110, 100, 170, 90, 120, 80, 140, 150, 160, 170, 165, 150],
 | 
					        consumptionData: generateYearlyDataInRange(200, 450),
 | 
				
			||||||
        generationData: [70, 80, 85, 95, 100, 110, 105, 140, 120, 150, 110, 130, 110, 130, 120, 130, 140, 145, 130],
 | 
					        generationData: generateYearlyDataInRange(200, 450),
 | 
				
			||||||
        systemStatus: 'Normal',
 | 
					        systemStatus: 'Normal',
 | 
				
			||||||
        temperature: '32°C',
 | 
					        temperature: '32°C',
 | 
				
			||||||
        solarPower: 95.2,
 | 
					        solarPower: 95.2,
 | 
				
			||||||
@ -66,15 +71,15 @@ export const mockSiteData: Record<SiteName, SiteDetails> = {
 | 
				
			|||||||
        installedPower: 150.0,
 | 
					        installedPower: 150.0,
 | 
				
			||||||
        gridImportPrice_RM_per_kWh: 0.52,
 | 
					        gridImportPrice_RM_per_kWh: 0.52,
 | 
				
			||||||
        solarExportTariff_RM_per_kWh: 0.32,
 | 
					        solarExportTariff_RM_per_kWh: 0.32,
 | 
				
			||||||
        theoreticalMaxGeneration_kWh: 20000,
 | 
					        theoreticalMaxGeneration_kWh: 190000,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    'Site C': {
 | 
					    'Site C': {
 | 
				
			||||||
        location: 'Johor Bahru, Johor',
 | 
					        location: 'Johor Bahru, Johor',
 | 
				
			||||||
        inverterProvider: 'Enphase',
 | 
					        inverterProvider: 'Enphase',
 | 
				
			||||||
        emergencyContact: '+60 13-555 1234',
 | 
					        emergencyContact: '+60 13-555 1234',
 | 
				
			||||||
        lastSyncTimestamp: '2025-06-03 08:00:00',
 | 
					        lastSyncTimestamp: '2025-06-03 08:00:00',
 | 
				
			||||||
        consumptionData: [110, 120, 130, 140, 135, 150, 145, 130, 120, 190, 110, 140, 100, 160, 170, 180, 190, 185, 170],
 | 
					        consumptionData: generateYearlyDataInRange(400, 550),
 | 
				
			||||||
        generationData: [50, 60, 65, 75, 80, 90, 85, 100, 90, 110, 80, 90, 80, 90, 80, 90, 100, 105, 90],
 | 
					        generationData: generateYearlyDataInRange(400, 550),
 | 
				
			||||||
        systemStatus: 'Faulty',
 | 
					        systemStatus: 'Faulty',
 | 
				
			||||||
        temperature: '30°C',
 | 
					        temperature: '30°C',
 | 
				
			||||||
        solarPower: 25.0,
 | 
					        solarPower: 25.0,
 | 
				
			||||||
@ -82,6 +87,6 @@ export const mockSiteData: Record<SiteName, SiteDetails> = {
 | 
				
			|||||||
        installedPower: 120.0,
 | 
					        installedPower: 120.0,
 | 
				
			||||||
        gridImportPrice_RM_per_kWh: 0.48,
 | 
					        gridImportPrice_RM_per_kWh: 0.48,
 | 
				
			||||||
        solarExportTariff_RM_per_kWh: 0.28,
 | 
					        solarExportTariff_RM_per_kWh: 0.28,
 | 
				
			||||||
        theoreticalMaxGeneration_kWh: 18000, // Lower theoretical max due to fault or smaller system
 | 
					        theoreticalMaxGeneration_kWh: 180000, // Lower theoretical max due to fault or smaller system
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user