diff --git a/packages/web/components/ProfileViewer_backup.tsx b/packages/web/components/ProfileViewer_backup.tsx deleted file mode 100644 index 697e01c..0000000 --- a/packages/web/components/ProfileViewer_backup.tsx +++ /dev/null @@ -1,632 +0,0 @@ -"use client"; - -import { useState, useCallback, useEffect } from "react"; -import { useQuery } from "@tanstack/react-query"; -import { - BarChart, - Bar, - XAxis, - YAxis, - Tooltip, - ResponsiveContainer, - ReferenceLine, - LineChart, - Line, - CartesianGrid, - Legend, -} from "recharts"; -import { - getAvailableProfiles, - getProfileStats, - getSolarProfile, - getWindProfile, - profileCsvUrl, - type ProfileStats, -} from "@/lib/api"; - -interface ProfileData { - solar: Record; // { locationId: [8760 values] } - wind: Record; - stats: Record; -} - -const LOCATIONS = [ - { id: "GJ", name: "Gujarat" }, - { id: "KA", name: "Karnataka" }, - { id: "RJ", name: "Rajasthan" }, -]; - -const SOLAR_COLOR = "#f97316"; // orange-500 -const WIND_COLOR = "#3b82f6"; // blue-500 -const UPLOAD_COLOR = "#8b5cf6"; // violet-500 - -interface StatsCardProps { - label: string; - value: string; - color?: string; -} - -function StatsCard({ label, value, color }: StatsCardProps) { - return ( -
-
{label}
-
- {value} -
-
- ); -} - -// Custom tooltip for charts -function CustomTooltip({ active, payload, label }: { active?: boolean; payload?: { value: number; name: string }[]; label?: string }) { - if (!active || !payload?.length) return null; - return ( -
-

{label}

- {payload.map((entry, i) => ( -
- - {entry.name}: - {(entry.value * 100).toFixed(2)}% -
- ))} -
- ); -} - -export function ProfileViewer() { - const [isOpen, setIsOpen] = useState(false); - const [activeTab, setActiveTab] = useState<"solar" | "wind" | "compare">("solar"); - const [uploadedProfiles, setUploadedProfiles] = useState<{ - solar?: number[]; - wind?: number[]; - filename?: string; - }>({}); - const [isUploading, setIsUploading] = useState(false); - const [uploadError, setUploadError] = useState(null); - const [selectedFile, setSelectedFile] = useState<{ - name: string; - path: string; - data: string[][]; - headers: string[]; - } | null>(null); - const [isLoadingFile, setIsLoadingFile] = useState(false); - - const API_BASE = typeof window !== 'undefined' - ? ((window as any).NEXT_PUBLIC_API_URL || 'http://localhost:8000') - : 'http://localhost:8000'; - - async function fetchAndDisplayFile(path: string, name: string) { - setIsLoadingFile(true); - try { - const res = await fetch(`${API_BASE}${path}`); - const text = await res.text(); - const lines = text.trim().split('\n'); - const headers = lines[0].split(','); - const data = lines.slice(1).map(line => line.split(',')); - setSelectedFile({ name, path, data, headers }); - } catch (err) { - console.error('Failed to fetch file:', err); - } finally { - setIsLoadingFile(false); - } - } - - // Calculate stats for a profile - const calculateStats = (data: number[]) => { - const sorted = [...data].sort((a, b) => a - b); - const sum = data.reduce((a, b) => a + b, 0); - return { - avg: sum / data.length, - max: Math.max(...data), - min: Math.min(...data), - median: sorted[Math.floor(sorted.length / 2)], - }; - }; - - // Handle file upload - const handleFileUpload = useCallback(async (event: React.ChangeEvent) => { - const file = event.target.files?.[0]; - if (!file) return; - - setIsUploading(true); - setUploadError(null); - - try { - const text = await file.text(); - const lines = text.trim().split("\n"); - - if (lines.length < 2) { - throw new Error("File must have at least a header row and one data row"); - } - - // Try to detect format - const header = lines[0].toLowerCase(); - let parsedData: number[] = []; - - if (header.includes("%_generation")) { - // New format: find the %_generation column - const cols = header.split(","); - const colIdx = cols.indexOf("%_generation"); - if (colIdx === -1) throw new Error("Could not find %_generation column"); - - parsedData = lines.slice(1).map((line) => { - const vals = line.split(","); - let val = parseFloat(vals[colIdx]); - if (isNaN(val)) return 0; - if (val > 1) val = val / 100; // Convert % to fraction - return val; - }); - } else if (header.includes("irradiance") || header.includes("wind_speed") || header.includes("e_grid")) { - // Old format: usually second column - parsedData = lines.slice(1).map((line) => { - const vals = line.split(","); - let val = parseFloat(vals[1]); - if (isNaN(val)) return 0; - // Handle different scales - if (val > 1) val = val / 1000; // Convert kW to MW - if (val > 1) val = val / 100; // Convert % to fraction - return val; - }); - } else { - // Generic: just take all numeric values from first column - parsedData = lines.slice(1).map((line) => { - const vals = line.split(","); - let val = parseFloat(vals[0]); - if (isNaN(val)) return 0; - return val; - }); - } - - // Validate 8760 values - if (parsedData.length !== 8760) { - throw new Error(`Expected 8760 values, got ${parsedData.length}`); - } - - // Determine if solar or wind based on average value (solar typically higher during day) - const isSolar = parsedData.reduce((a, b, i) => { - // Solar has high values during midday hours (indices 6-18 of each day) - const hourOfDay = i % 24; - if (hourOfDay >= 6 && hourOfDay <= 18) return a + b; - return a; - }, 0) / parsedData.reduce((a, b) => a + b, 0) > 0.7; - - setUploadedProfiles({ - solar: isSolar ? parsedData : undefined, - wind: !isSolar ? parsedData : undefined, - filename: file.name, - }); - } catch (err) { - setUploadError(err instanceof Error ? err.message : "Failed to parse file"); - } finally { - setIsUploading(false); - } - }, []); - - // Generate monthly averages for chart - const getMonthlyAverages = (data: number[], isSolar: boolean) => { - const MONTH_DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; - const monthNames = ["Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan", "Feb", "Mar"]; - const monthPositions = [4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3]; - - return monthNames.map((name, i) => { - const month = monthPositions[i]; - const start = MONTH_DAYS.slice(0, month - 1).reduce((a, d) => a + d, 0) * 24; - const days = MONTH_DAYS[month - 1]; - const monthData = data.slice(start, start + days * 24); - const avg = monthData.reduce((a, b) => a + b, 0) / monthData.length; - return { name, avg: avg * 100 }; - }); - }; - - // Generate hourly average profile for a typical day - const getHourlyAverage = (data: number[]) => { - const hourly = new Array(24).fill(0); - for (let i = 0; i < 8760; i++) { - hourly[i % 24] += data[i]; - } - return hourly.map((v) => v / 365); - }; - - return ( - <> - {/* Button to open the modal */} - - - {/* Modal */} - {isOpen && ( -
- {/* Backdrop */} -
setIsOpen(false)} - /> - - {/* Modal content */} -
- {/* Header */} -
-

File Reference Library

- -
- - {/* Tabs */} -
- - - -
- - {/* Upload section */} -
-
- - {uploadError && ( - {uploadError} - )} -
-
- - {/* Content */} -
- {/* File preview section - ALWAYS SHOWS when file is selected */} - {selectedFile ? ( -
-
-
- {selectedFile.name.includes('Solar') ? '☀️' : '💨'} -
-

{selectedFile.name}

-

{selectedFile.data.length} rows of data

-
-
-
- - Download CSV - - -
-
-
- - - - - - - - - - - - - {selectedFile.data.map((row: string[], i: number) => ( - - - - - - - - - ))} - -
HourDateMonthDayHour of Day% Generation
{row[0]}{row[1]}{row[2]}{row[3]}{row[4]}{row[5]}
-
-
- ) : ( -
- {/* Bundled profiles section - shown when no file selected */} -
-

📂 Click on any file below to view its contents:

-
- {[ - { name: "Solar - Gujarat", path: "/api/profiles/solar/GJ", type: "solar", id: "solar_gj" }, - { name: "Solar - Karnataka", path: "/api/profiles/solar/KA", type: "solar", id: "solar_ka" }, - { name: "Solar - Rajasthan", path: "/api/profiles/solar/RJ", type: "solar", id: "solar_rj" }, - { name: "Wind - Gujarat", path: "/api/profiles/wind/GJ", type: "wind", id: "wind_gj" }, - { name: "Wind - Karnataka", path: "/api/profiles/wind/KA", type: "wind", id: "wind_ka" }, - { name: "Wind - Rajasthan", path: "/api/profiles/wind/RJ", type: "wind", id: "wind_rj" }, - ].map((profile) => ( - - ))} -
-
- - {/* Charts section - hidden when file is selected */} - {!selectedFile && activeTab === "solar" && ( -
-
-

- Monthly Average Solar Irradiance -

-
- - { - // Mock data for demonstration - in real app this would come from API - const mockData = Array(8760).fill(0).map((_, i) => { - const hour = i % 24; - const dayOfYear = Math.floor(i / 24); - // Simple sinusoidal approximation - const solarNoon = Math.sin((hour - 6) * Math.PI / 12); - const seasonFactor = Math.sin((dayOfYear - 80) * 2 * Math.PI / 365); - return Math.max(0, solarNoon * (0.8 + 0.2 * seasonFactor)); - }); - const monthly = getMonthlyAverages(mockData, true); - const idx = ["GJ", "KA", "RJ"].indexOf(loc.id); - return { - name: loc.name, - Jan: monthly[9]?.avg || 0, - Feb: monthly[10]?.avg || 0, - Mar: monthly[11]?.avg || 0, - Apr: monthly[0]?.avg || 0, - May: monthly[1]?.avg || 0, - Jun: monthly[2]?.avg || 0, - Jul: monthly[3]?.avg || 0, - Aug: monthly[4]?.avg || 0, - Sep: monthly[5]?.avg || 0, - Oct: monthly[6]?.avg || 0, - Nov: monthly[7]?.avg || 0, - Dec: monthly[8]?.avg || 0, - [idx]: 0, - }; - })}> - - - } /> - - - - - - -
-
- - {uploadedProfiles.solar && ( -
-

- Your Uploaded Solar Profile -

-
- {(() => { - const stats = calculateStats(uploadedProfiles.solar!); - return ( - <> - - - - - - ); - })()} -
-
- )} -
- )} - - {activeTab === "wind" && ( -
-
-

- Monthly Average Wind Speed (m/s) -

-
- - - - - - - - -
-
- - {uploadedProfiles.wind && ( -
-

- Your Uploaded Wind Profile -

-
- {(() => { - const stats = calculateStats(uploadedProfiles.wind!); - return ( - <> - - - - - - ); - })()} -
-
- )} -
- )} - - {!selectedFile && activeTab === "compare" && ( -
-
-

- Solar vs Wind CUF (Typical Daily Pattern) -

-
- - { - const hour = i % 24; - const solarValue = Math.max(0, Math.sin((hour - 6) * Math.PI / 12)); - const windValue = 0.3 + 0.2 * Math.sin(i * Math.PI / 12) + 0.1 * Math.random(); - return (solarValue + windValue) / 2; - }) - ).map((v, i) => ({ hour: `${String(i).padStart(2, '0')}:00`, Solar: v, Wind: 0.3 + 0.1 * Math.sin(i * Math.PI / 12) }))}> - - - `${(v * 100).toFixed(0)}%`} /> - } /> - - - - - -
-
- - {uploadedProfiles.solar && uploadedProfiles.wind && ( -
-

- Your Uploaded Profiles Comparison -

-
- {(() => { - const solarStats = calculateStats(uploadedProfiles.solar!); - const windStats = calculateStats(uploadedProfiles.wind!); - return ( - <> - - - - - - ); - })()} -
-
- )} -
- )} -
-
-
- )} - - ); -}