feature/syasya/testlayout #7
@ -9,6 +9,8 @@ import DashboardLayout from './dashlayout';
 | 
				
			|||||||
import html2canvas from 'html2canvas';
 | 
					import html2canvas from 'html2canvas';
 | 
				
			||||||
import jsPDF from 'jspdf';
 | 
					import jsPDF from 'jspdf';
 | 
				
			||||||
import dynamic from 'next/dynamic';
 | 
					import dynamic from 'next/dynamic';
 | 
				
			||||||
 | 
					import { fetchPowerTimeseries } from '@/app/utils/api';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const EnergyLineChart = dynamic(() => import('@/components/dashboards/EnergyLineChart'), {
 | 
					const EnergyLineChart = dynamic(() => import('@/components/dashboards/EnergyLineChart'), {
 | 
				
			||||||
  ssr: false,
 | 
					  ssr: false,
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
@ -45,6 +47,53 @@ const AdminDashboard = () => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }, [siteParam, selectedSite]);
 | 
					  }, [siteParam, selectedSite]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [timeSeriesData, setTimeSeriesData] = useState<{
 | 
				
			||||||
 | 
					    consumption: { time: string; value: number }[];
 | 
				
			||||||
 | 
					    generation: { time: string; value: number }[];
 | 
				
			||||||
 | 
					  }>({ consumption: [], generation: [] });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					  const fetchData = async () => {
 | 
				
			||||||
 | 
					    const siteIdMap: Record<SiteName, string> = {
 | 
				
			||||||
 | 
					  'Site A': 'site_01',
 | 
				
			||||||
 | 
					  'Site B': 'site_02',
 | 
				
			||||||
 | 
					  'Site C': 'site_03',
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const siteId = siteIdMap[selectedSite];
 | 
				
			||||||
 | 
					  const today = new Date();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Format to YYYY-MM-DD
 | 
				
			||||||
 | 
					  const yyyyMMdd = today.toISOString().split('T')[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Append Malaysia's +08:00 time zone manually
 | 
				
			||||||
 | 
					  const start = `${yyyyMMdd}T00:00:00+08:00`;
 | 
				
			||||||
 | 
					  const end = `${yyyyMMdd}T23:59:59+08:00`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const raw = await fetchPowerTimeseries(siteId, start, end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const consumption = raw.consumption.map(d => ({
 | 
				
			||||||
 | 
					      time: d.time,
 | 
				
			||||||
 | 
					      value: d.value,
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const generation = raw.generation.map(d => ({
 | 
				
			||||||
 | 
					      time: d.time,
 | 
				
			||||||
 | 
					      value: d.value,
 | 
				
			||||||
 | 
					    }));  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setTimeSeriesData({ consumption, generation });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					      console.error('Failed to fetch power time series:', error);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fetchData();
 | 
				
			||||||
 | 
					}, [selectedSite]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Update query string when site is changed manually
 | 
					  // Update query string when site is changed manually
 | 
				
			||||||
  const handleSiteChange = (newSite: SiteName) => {
 | 
					  const handleSiteChange = (newSite: SiteName) => {
 | 
				
			||||||
    setSelectedSite(newSite);
 | 
					    setSelectedSite(newSite);
 | 
				
			||||||
@ -142,9 +191,11 @@ const AdminDashboard = () => {
 | 
				
			|||||||
        <div className="grid md:grid-cols-2 gap-6 lg:flex-col justify-center">
 | 
					        <div className="grid md:grid-cols-2 gap-6 lg:flex-col justify-center">
 | 
				
			||||||
          <div ref={energyChartRef} className="pb-5">
 | 
					          <div ref={energyChartRef} className="pb-5">
 | 
				
			||||||
            <EnergyLineChart
 | 
					            <EnergyLineChart
 | 
				
			||||||
              consumptionData={currentSiteDetails.consumptionData}
 | 
					  consumption={timeSeriesData.consumption}
 | 
				
			||||||
              generationData={currentSiteDetails.generationData}
 | 
					  generation={timeSeriesData.generation}
 | 
				
			||||||
/>
 | 
					/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
          <div ref={monthlyChartRef} className="pb-5">
 | 
					          <div ref={monthlyChartRef} className="pb-5">
 | 
				
			||||||
            <MonthlyBarChart siteData={currentSiteDetails} />
 | 
					            <MonthlyBarChart siteData={currentSiteDetails} />
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										28
									
								
								app/utils/api.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								app/utils/api.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					// app/utils/api.ts
 | 
				
			||||||
 | 
					export interface TimeSeriesEntry {
 | 
				
			||||||
 | 
					  time: string;
 | 
				
			||||||
 | 
					  value: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface TimeSeriesResponse {
 | 
				
			||||||
 | 
					  consumption: TimeSeriesEntry[];
 | 
				
			||||||
 | 
					  generation: TimeSeriesEntry[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function fetchPowerTimeseries(
 | 
				
			||||||
 | 
					  site: string,
 | 
				
			||||||
 | 
					  start: string,
 | 
				
			||||||
 | 
					  end: string
 | 
				
			||||||
 | 
					): Promise<TimeSeriesResponse> { // <-- Change here
 | 
				
			||||||
 | 
					  const params = new URLSearchParams({ site, start, end });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const res = await fetch(`http://localhost:8000/power-timeseries?${params.toString()}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!res.ok) {
 | 
				
			||||||
 | 
					    throw new Error(`Failed to fetch data: ${res.status}`);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const json = await res.json();
 | 
				
			||||||
 | 
					  console.log(`🔍 API response from /power-timeseries?${params.toString()}:`, json); // ✅ log here
 | 
				
			||||||
 | 
					  return json; // <-- This is a single object, not an array
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -5,23 +5,31 @@ import zoomPlugin from 'chartjs-plugin-zoom';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
ChartJS.register(zoomPlugin);
 | 
					ChartJS.register(zoomPlugin);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface EnergyLineChartProps {
 | 
					interface TimeSeriesEntry {
 | 
				
			||||||
  consumptionData: number[];
 | 
					  time: string;
 | 
				
			||||||
  generationData: number[];
 | 
					  value: number;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const labels = [
 | 
					interface EnergyLineChartProps {
 | 
				
			||||||
  '08:00', '08:30', '09:00', '09:30', '10:00',
 | 
					  consumption: TimeSeriesEntry[];
 | 
				
			||||||
  '10:30', '11:00', '11:30', '12:00', '12:30',
 | 
					  generation: TimeSeriesEntry[];
 | 
				
			||||||
  '13:00', '13:30', '14:00', '14:30', '15:00',
 | 
					}
 | 
				
			||||||
  '15:30', '16:00', '16:30', '17:00',
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const EnergyLineChart = ({ consumptionData, generationData }: EnergyLineChartProps) => {
 | 
					const EnergyLineChart = ({ consumption, generation }: EnergyLineChartProps) => {
 | 
				
			||||||
  const chartRef = useRef<any>(null);
 | 
					  const chartRef = useRef<any>(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Generate sorted unique time labels from both series
 | 
				
			||||||
 | 
					  const allTimes = Array.from(new Set([
 | 
				
			||||||
 | 
					    ...consumption.map(d => d.time),
 | 
				
			||||||
 | 
					    ...generation.map(d => d.time),
 | 
				
			||||||
 | 
					  ])).sort(); // e.g., ["00:00", "00:30", "01:00", ...]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Map times to values
 | 
				
			||||||
 | 
					  const consumptionMap = Object.fromEntries(consumption.map(d => [d.time, d.value]));
 | 
				
			||||||
 | 
					  const generationMap = Object.fromEntries(generation.map(d => [d.time, d.value]));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const [startIndex, setStartIndex] = useState(0);
 | 
					  const [startIndex, setStartIndex] = useState(0);
 | 
				
			||||||
  const [endIndex, setEndIndex] = useState(labels.length - 1);
 | 
					  const [endIndex, setEndIndex] = useState(allTimes.length - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    if (typeof window !== 'undefined') {
 | 
					    if (typeof window !== 'undefined') {
 | 
				
			||||||
@ -29,14 +37,13 @@ const EnergyLineChart = ({ consumptionData, generationData }: EnergyLineChartPro
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }, []);
 | 
					  }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Filter data arrays based on selected range
 | 
					  const filteredLabels = allTimes.slice(startIndex, endIndex + 1);
 | 
				
			||||||
  const filteredConsumption = consumptionData.slice(startIndex, endIndex + 1);
 | 
					  const filteredConsumption = filteredLabels.map(t => consumptionMap[t] ?? null);
 | 
				
			||||||
  const filteredGeneration = generationData.slice(startIndex, endIndex + 1);
 | 
					  const filteredGeneration = filteredLabels.map(t => generationMap[t] ?? null);
 | 
				
			||||||
  const filteredLabels = labels.slice(startIndex, endIndex + 1);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const allDataPoints = [...filteredConsumption, ...filteredGeneration];
 | 
					  const allValues = [...filteredConsumption, ...filteredGeneration].filter(v => v !== null) as number[];
 | 
				
			||||||
  const maxDataValue = allDataPoints.length > 0 ? Math.max(...allDataPoints) : 0;
 | 
					  const maxValue = allValues.length > 0 ? Math.max(...allValues) : 0;
 | 
				
			||||||
  const yAxisSuggestedMax = maxDataValue * 1.15;
 | 
					  const yAxisSuggestedMax = maxValue * 1.15;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const data = {
 | 
					  const data = {
 | 
				
			||||||
    labels: filteredLabels,
 | 
					    labels: filteredLabels,
 | 
				
			||||||
@ -74,9 +81,29 @@ const EnergyLineChart = ({ consumptionData, generationData }: EnergyLineChartPro
 | 
				
			|||||||
    tooltip: { enabled: true, mode: 'index' as const, intersect: false },
 | 
					    tooltip: { enabled: true, mode: 'index' as const, intersect: false },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  scales: {
 | 
					  scales: {
 | 
				
			||||||
      y: { beginAtZero: true, suggestedMax: yAxisSuggestedMax },
 | 
					    x: {
 | 
				
			||||||
 | 
					      title: {
 | 
				
			||||||
 | 
					        display: true,
 | 
				
			||||||
 | 
					        text: 'Time (HH:MM)',
 | 
				
			||||||
 | 
					        font: {
 | 
				
			||||||
 | 
					          weight: 'bold' as const, // ✅ FIX: cast as 'const'
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
  };
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    y: {
 | 
				
			||||||
 | 
					      beginAtZero: true,
 | 
				
			||||||
 | 
					      suggestedMax: yAxisSuggestedMax,
 | 
				
			||||||
 | 
					      title: {
 | 
				
			||||||
 | 
					        display: true,
 | 
				
			||||||
 | 
					        text: 'Power (kW)',
 | 
				
			||||||
 | 
					        font: {
 | 
				
			||||||
 | 
					          weight: 'bold' as const, // ✅ FIX: cast as 'const'
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					} as const; // ✅ Ensures compatibility with chart.js types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleResetZoom = () => {
 | 
					  const handleResetZoom = () => {
 | 
				
			||||||
    chartRef.current?.resetZoom();
 | 
					    chartRef.current?.resetZoom();
 | 
				
			||||||
@ -104,10 +131,8 @@ const EnergyLineChart = ({ consumptionData, generationData }: EnergyLineChartPro
 | 
				
			|||||||
              }}
 | 
					              }}
 | 
				
			||||||
              className="border rounded p-1"
 | 
					              className="border rounded p-1"
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              {labels.map((label, idx) => (
 | 
					              {allTimes.map((label, idx) => (
 | 
				
			||||||
                <option key={idx} value={idx}>
 | 
					                <option key={idx} value={idx}>{label}</option>
 | 
				
			||||||
                  {label}
 | 
					 | 
				
			||||||
                </option>
 | 
					 | 
				
			||||||
              ))}
 | 
					              ))}
 | 
				
			||||||
            </select>
 | 
					            </select>
 | 
				
			||||||
          </label>
 | 
					          </label>
 | 
				
			||||||
@ -121,10 +146,8 @@ const EnergyLineChart = ({ consumptionData, generationData }: EnergyLineChartPro
 | 
				
			|||||||
              }}
 | 
					              }}
 | 
				
			||||||
              className="border rounded p-1"
 | 
					              className="border rounded p-1"
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              {labels.map((label, idx) => (
 | 
					              {allTimes.map((label, idx) => (
 | 
				
			||||||
                <option key={idx} value={idx}>
 | 
					                <option key={idx} value={idx}>{label}</option>
 | 
				
			||||||
                  {label}
 | 
					 | 
				
			||||||
                </option>
 | 
					 | 
				
			||||||
              ))}
 | 
					              ))}
 | 
				
			||||||
            </select>
 | 
					            </select>
 | 
				
			||||||
          </label>
 | 
					          </label>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,31 @@
 | 
				
			|||||||
// types/siteData.ts
 | 
					// types/siteData.ts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const generateDailyData = (
 | 
				
			||||||
 | 
					  type: 'consumption' | 'generation',
 | 
				
			||||||
 | 
					  min: number,
 | 
				
			||||||
 | 
					  max: number
 | 
				
			||||||
 | 
					): { time: string; value: number }[] => {
 | 
				
			||||||
 | 
					  return Array.from({ length: 48 }, (_, i) => {
 | 
				
			||||||
 | 
					    const hour = Math.floor(i / 2);
 | 
				
			||||||
 | 
					    const minute = i % 2 === 0 ? '00' : '30';
 | 
				
			||||||
 | 
					    const time = `${hour.toString().padStart(2, '0')}:${minute}`;
 | 
				
			||||||
 | 
					    let value = Math.random() * (max - min) + min;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (type === 'generation') {
 | 
				
			||||||
 | 
					      if (hour < 8 || hour >= 18) {
 | 
				
			||||||
 | 
					        value = 0;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        const peakHour = 13;
 | 
				
			||||||
 | 
					        const offset = Math.abs(hour + (i % 2 === 0 ? 0 : 0.5) - peakHour);
 | 
				
			||||||
 | 
					        value = Math.max(0, max - offset * 5 + Math.random() * 5);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return { time, value: parseFloat(value.toFixed(2)) };
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type SiteName = 'Site A' | 'Site B' | 'Site C';
 | 
					export type SiteName = 'Site A' | 'Site B' | 'Site C';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface SiteDetails {
 | 
					export interface SiteDetails {
 | 
				
			||||||
@ -16,13 +43,10 @@ export interface SiteDetails {
 | 
				
			|||||||
    realTimePower: number; // Real-time power used (kW)
 | 
					    realTimePower: number; // Real-time power used (kW)
 | 
				
			||||||
    installedPower: number; // Installed capacity (kWp)
 | 
					    installedPower: number; // Installed capacity (kWp)
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // New properties for KPI calculations (assuming these are base values for the month)
 | 
					      dailyTimeSeriesData: {
 | 
				
			||||||
    // If consumptionData/generationData are daily, we will sum them up.
 | 
					    consumption: { time: string; value: number }[];
 | 
				
			||||||
    // If they were monthly totals, you'd name them appropriately.
 | 
					    generation: { time: string; value: number }[];
 | 
				
			||||||
    // Let's assume these are the *raw data points* for the month.
 | 
					  };
 | 
				
			||||||
    // monthlyConsumptionkWh?: number; // Optional, if you want to store a pre-calculated total
 | 
					 | 
				
			||||||
    // monthlyGenerationkWh?: number; // Optional, if you want to store a pre-calculated total
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    // For savings calculation:
 | 
					    // For savings calculation:
 | 
				
			||||||
    gridImportPrice_RM_per_kWh: number; // Price paid for electricity from the grid
 | 
					    gridImportPrice_RM_per_kWh: number; // Price paid for electricity from the grid
 | 
				
			||||||
    solarExportTariff_RM_per_kWh: number; // Price received for excess solar sent to grid (e.g., FiT)
 | 
					    solarExportTariff_RM_per_kWh: number; // Price received for excess solar sent to grid (e.g., FiT)
 | 
				
			||||||
@ -40,7 +64,12 @@ const generateYearlyDataInRange = (min: number, max: number) =>
 | 
				
			|||||||
    .map(() => Math.floor(Math.random() * (max - min + 1)) + min);
 | 
					    .map(() => Math.floor(Math.random() * (max - min + 1)) + min);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const mockSiteData: Record<SiteName, SiteDetails> = {
 | 
					export const mockSiteData: Record<SiteName, SiteDetails & {
 | 
				
			||||||
 | 
					  dailyTimeSeriesData: {
 | 
				
			||||||
 | 
					    consumption: { time: string; value: number }[];
 | 
				
			||||||
 | 
					    generation: { time: string; value: number }[];
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}> = {
 | 
				
			||||||
  'Site A': {
 | 
					  'Site A': {
 | 
				
			||||||
    location: 'Petaling Jaya, Selangor',
 | 
					    location: 'Petaling Jaya, Selangor',
 | 
				
			||||||
    inverterProvider: 'SolarEdge',
 | 
					    inverterProvider: 'SolarEdge',
 | 
				
			||||||
@ -52,11 +81,15 @@ export const mockSiteData: Record<SiteName, SiteDetails> = {
 | 
				
			|||||||
    temperature: '35°C',
 | 
					    temperature: '35°C',
 | 
				
			||||||
    solarPower: 108.4,
 | 
					    solarPower: 108.4,
 | 
				
			||||||
    realTimePower: 108.4,
 | 
					    realTimePower: 108.4,
 | 
				
			||||||
        installedPower: 174.9, // kWp
 | 
					    installedPower: 174.9,
 | 
				
			||||||
        gridImportPrice_RM_per_kWh: 0.50, // Example: RM 0.50 per kWh
 | 
					    gridImportPrice_RM_per_kWh: 0.50,
 | 
				
			||||||
        solarExportTariff_RM_per_kWh: 0.30, // Example: RM 0.30 per kWh
 | 
					    solarExportTariff_RM_per_kWh: 0.30,
 | 
				
			||||||
        theoreticalMaxGeneration_kWh: 80000, // Example: Theoretical max for 174.9 kWp over a month in Malaysia
 | 
					    theoreticalMaxGeneration_kWh: 80000,
 | 
				
			||||||
    connectedDevices: [],
 | 
					    connectedDevices: [],
 | 
				
			||||||
 | 
					    dailyTimeSeriesData: {
 | 
				
			||||||
 | 
					      consumption: generateDailyData('consumption', 80, 250),
 | 
				
			||||||
 | 
					      generation: generateDailyData('generation', 80, 100),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  'Site B': {
 | 
					  'Site B': {
 | 
				
			||||||
    location: 'Kuala Lumpur, Wilayah Persekutuan',
 | 
					    location: 'Kuala Lumpur, Wilayah Persekutuan',
 | 
				
			||||||
@ -74,6 +107,10 @@ export const mockSiteData: Record<SiteName, SiteDetails> = {
 | 
				
			|||||||
    solarExportTariff_RM_per_kWh: 0.32,
 | 
					    solarExportTariff_RM_per_kWh: 0.32,
 | 
				
			||||||
    theoreticalMaxGeneration_kWh: 190000,
 | 
					    theoreticalMaxGeneration_kWh: 190000,
 | 
				
			||||||
    connectedDevices: [],
 | 
					    connectedDevices: [],
 | 
				
			||||||
 | 
					    dailyTimeSeriesData: {
 | 
				
			||||||
 | 
					      consumption: generateDailyData('consumption', 150, 300),
 | 
				
			||||||
 | 
					      generation: generateDailyData('generation', 0, 120),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  'Site C': {
 | 
					  'Site C': {
 | 
				
			||||||
    location: 'Johor Bahru, Johor',
 | 
					    location: 'Johor Bahru, Johor',
 | 
				
			||||||
@ -89,7 +126,11 @@ 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: 180000, // Lower theoretical max due to fault or smaller system
 | 
					    theoreticalMaxGeneration_kWh: 180000,
 | 
				
			||||||
    connectedDevices: [],
 | 
					    connectedDevices: [],
 | 
				
			||||||
 | 
					    dailyTimeSeriesData: {
 | 
				
			||||||
 | 
					      consumption: generateDailyData('consumption', 100, 200),
 | 
				
			||||||
 | 
					      generation: generateDailyData('generation', 0, 90),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user