From d418dd77f23ab24e91dfebad94832f9496eb567d Mon Sep 17 00:00:00 2001
From: Navan Chauhan <navanchauhan@gmail.com>
Date: Mon, 28 Apr 2025 00:20:28 -0600
Subject: prettifier

---
 client/src/components/MarketDataPage.jsx | 257 +++++++++++++++++++------------
 1 file changed, 161 insertions(+), 96 deletions(-)

(limited to 'client/src/components/MarketDataPage.jsx')

diff --git a/client/src/components/MarketDataPage.jsx b/client/src/components/MarketDataPage.jsx
index 9d98269..eed970f 100644
--- a/client/src/components/MarketDataPage.jsx
+++ b/client/src/components/MarketDataPage.jsx
@@ -1,10 +1,10 @@
-import React, { useEffect, useState, useContext, useRef, useMemo } from 'react';
-import { Typography, Spin, Message, Card, Grid } from '@arco-design/web-react';
-import '@arco-design/web-react/dist/css/arco.css';
-import { initVChartArcoTheme } from '@visactor/vchart-arco-theme';
-import { VChart } from '@visactor/react-vchart';
-import API_BASE_URL from '../config';
-import { MarketContext, MARKET_FULL_NAMES } from '../App';
+import React, { useEffect, useState, useContext, useRef, useMemo } from "react";
+import { Typography, Spin, Message, Card, Grid } from "@arco-design/web-react";
+import "@arco-design/web-react/dist/css/arco.css";
+import { initVChartArcoTheme } from "@visactor/vchart-arco-theme";
+import { VChart } from "@visactor/react-vchart";
+import API_BASE_URL from "../config";
+import { MarketContext, MARKET_FULL_NAMES } from "../App";
 
 // TODO:
 //
@@ -22,7 +22,7 @@ function TimeAgo({ timestamp, prefix }) {
   }, []);
 
   const formatTimeAgo = () => {
-    if (!timestamp) return '';
+    if (!timestamp) return "";
     const seconds = Math.floor((now - timestamp) / 1000);
     if (seconds < 60) return `${seconds} sec ago`;
     const minutes = Math.floor(seconds / 60);
@@ -32,7 +32,10 @@ function TimeAgo({ timestamp, prefix }) {
   };
 
   return (
-    <Typography.Text type="secondary" style={{ fontSize: 12, display: 'block', marginTop: 8 }}>
+    <Typography.Text
+      type="secondary"
+      style={{ fontSize: 12, display: "block", marginTop: 8 }}
+    >
       {prefix}: {formatTimeAgo()}
     </Typography.Text>
   );
@@ -41,7 +44,7 @@ function TimeAgo({ timestamp, prefix }) {
 function MarketDataPage() {
   const { selectedMarket } = useContext(MarketContext);
   const fiveMinChartRef = useRef(null);
-    const dayAheadChartRef = useRef(null);
+  const dayAheadChartRef = useRef(null);
   const [fiveMinZoom, setFiveMinZoom] = useState({ start: 0.9, end: 1 });
   const [dayAheadZoom, setDayAheadZoom] = useState({ start: 0.05, end: 1 });
   const [fiveMinData, setFiveMinData] = useState([]);
@@ -52,38 +55,42 @@ function MarketDataPage() {
   const [, setNow] = useState(new Date());
 
   const handleZoomChange = (e, title) => {
-     if (!e?.start || !e?.end) return;
-     if (title === 'fiveMin') {
-       setFiveMinZoom({ start: e.start, end: e.end });
-     } else {
-       setDayAheadZoom({ start: e.start, end: e.end });
-     }
-   };
+    if (!e?.start || !e?.end) return;
+    if (title === "fiveMin") {
+      setFiveMinZoom({ start: e.start, end: e.end });
+    } else {
+      setDayAheadZoom({ start: e.start, end: e.end });
+    }
+  };
 
   useEffect(() => {
     const fetchFiveMinData = async () => {
       try {
-        const res = await fetch(`${API_BASE_URL}/market/real-time?market=${selectedMarket}`);
-        if (!res.ok) throw new Error('Failed to fetch real-time data');
+        const res = await fetch(
+          `${API_BASE_URL}/market/real-time?market=${selectedMarket}`,
+        );
+        if (!res.ok) throw new Error("Failed to fetch real-time data");
         const json = await res.json();
         setFiveMinData(json);
         setFiveMinLastUpdated(new Date());
       } catch (err) {
         console.error(err);
-        Message.error('Failed to load real-time market data.');
+        Message.error("Failed to load real-time market data.");
       }
     };
 
     const fetchDayAheadData = async () => {
       try {
-        const res = await fetch(`${API_BASE_URL}/market/day-ahead?market=${selectedMarket}`);
-        if (!res.ok) throw new Error('Failed to fetch day-ahead data');
+        const res = await fetch(
+          `${API_BASE_URL}/market/day-ahead?market=${selectedMarket}`,
+        );
+        if (!res.ok) throw new Error("Failed to fetch day-ahead data");
         const json = await res.json();
         setDayAheadData(json);
         setDayAheadLastUpdated(new Date());
       } catch (err) {
         console.error(err);
-        Message.error('Failed to load day-ahead market data.');
+        Message.error("Failed to load day-ahead market data.");
       }
     };
 
@@ -93,8 +100,8 @@ function MarketDataPage() {
       setLoading(false);
 
       initVChartArcoTheme({
-        defaultMode: 'light',
-        isWatchingMode: true
+        defaultMode: "light",
+        isWatchingMode: true,
       });
     };
 
@@ -111,79 +118,102 @@ function MarketDataPage() {
     };
   }, [selectedMarket]);
 
-  const fiveMinSpec = useMemo(() => ({
-      type: 'line',
+  const fiveMinSpec = useMemo(
+    () => ({
+      type: "line",
       data: {
-        values: fiveMinData.map(d => ({
+        values: fiveMinData.map((d) => ({
           timestamp: new Date(d.timestamp).toLocaleString(),
           LMP: d.lmp,
           Energy: d.energy,
           Congestion: d.congestion,
-          Loss: d.loss
+          Loss: d.loss,
         })),
-        transforms: [{
-          type: 'fold',
-          options: { key: 'name', value: 'value', fields: ['LMP', 'Energy', 'Congestion', 'Loss'] }
-        }]
+        transforms: [
+          {
+            type: "fold",
+            options: {
+              key: "name",
+              value: "value",
+              fields: ["LMP", "Energy", "Congestion", "Loss"],
+            },
+          },
+        ],
       },
-      xField: 'timestamp',
-      yField: 'value',
-      seriesField: 'name',
+      xField: "timestamp",
+      yField: "value",
+      seriesField: "name",
       smooth: true,
-      legend: { position: 'top' },
+      legend: { position: "top" },
       tooltip: {
         formatter: (datum) => ({
           name: datum.name,
-          value: datum.value.toFixed(2)
-        })
+          value: datum.value.toFixed(2),
+        }),
       },
-      dataZoom: [{
-        orient: 'bottom',
-        height: 20,
-        start: fiveMinZoom.start,
-        end: fiveMinZoom.end
-      }]
-    }), [fiveMinData, fiveMinZoom]); // <== DEPENDENCIES
+      dataZoom: [
+        {
+          orient: "bottom",
+          height: 20,
+          start: fiveMinZoom.start,
+          end: fiveMinZoom.end,
+        },
+      ],
+    }),
+    [fiveMinData, fiveMinZoom],
+  ); // <== DEPENDENCIES
 
-    const dayAheadSpec = useMemo(() => ({
-      type: 'line',
+  const dayAheadSpec = useMemo(
+    () => ({
+      type: "line",
       data: {
-        values: dayAheadData.map(d => ({
+        values: dayAheadData.map((d) => ({
           timestamp: new Date(d.timestamp).toLocaleString(),
           LMP: d.lmp,
           Energy: d.energy,
           Congestion: d.congestion,
-          Loss: d.loss
+          Loss: d.loss,
         })),
-        transforms: [{
-          type: 'fold',
-          options: { key: 'name', value: 'value', fields: ['LMP', 'Energy', 'Congestion', 'Loss'] }
-        }]
+        transforms: [
+          {
+            type: "fold",
+            options: {
+              key: "name",
+              value: "value",
+              fields: ["LMP", "Energy", "Congestion", "Loss"],
+            },
+          },
+        ],
       },
-      xField: 'timestamp',
-      yField: 'value',
-      seriesField: 'name',
+      xField: "timestamp",
+      yField: "value",
+      seriesField: "name",
       smooth: true,
-      legend: { position: 'top' },
+      legend: { position: "top" },
       tooltip: {
         formatter: (datum) => ({
           name: datum.name,
-          value: datum.value.toFixed(2)
-        })
+          value: datum.value.toFixed(2),
+        }),
       },
-      dataZoom: [{
-        orient: 'bottom',
-        height: 20,
-        start: dayAheadZoom.start,
-        end: dayAheadZoom.end
-      }]
-    }), [dayAheadData, dayAheadZoom]);
+      dataZoom: [
+        {
+          orient: "bottom",
+          height: 20,
+          start: dayAheadZoom.start,
+          end: dayAheadZoom.end,
+        },
+      ],
+    }),
+    [dayAheadData, dayAheadZoom],
+  );
 
   const computeKPIs = (data) => {
-    if (!data.length) return { avgLmp: 0, totalEnergy: 0, maxCongestion: 0, avgLoss: 0 };
+    if (!data.length)
+      return { avgLmp: 0, totalEnergy: 0, maxCongestion: 0, avgLoss: 0 };
     const avgLmp = data.reduce((sum, d) => sum + d.lmp, 0) / data.length;
     const totalEnergy = data.reduce((sum, d) => sum + d.energy, 0);
-    const maxCongestion = Math.max(...data.map(d => d.congestion));
+    const maxCongestion = Math.max(...data.map((d) => d.congestion));
     const avgLoss = data.reduce((sum, d) => sum + d.loss, 0) / data.length;
     return { avgLmp, totalEnergy, maxCongestion, avgLoss };
   };
@@ -193,32 +223,44 @@ function MarketDataPage() {
 
   return (
     <div className="page-container">
-      <Typography.Title heading={3} style={{ textAlign: 'center', marginBottom: 20 }} className="market-page-title" >
+      <Typography.Title
+        heading={3}
+        style={{ textAlign: "center", marginBottom: 20 }}
+        className="market-page-title"
+      >
         Market Data for {MARKET_FULL_NAMES[selectedMarket]}
       </Typography.Title>
 
       {loading ? (
-        <Spin style={{ display: 'block', margin: '80px auto' }} />
+        <Spin style={{ display: "block", margin: "80px auto" }} />
       ) : (
         <>
-         <Row gutter={24} style={{ marginBottom: 30 }}>
+          <Row gutter={24} style={{ marginBottom: 30 }}>
             {[
-              { label: 'Avg Real-Time LMP ($/MWh)', value: fiveMinKPIs.avgLmp },
-              { label: 'Total Real-Time Energy (MWh)', value: fiveMinKPIs.totalEnergy },
-              { label: 'Max Real-Time Congestion ($)', value: fiveMinKPIs.maxCongestion },
-              { label: 'Avg Real-Time Loss ($)', value: fiveMinKPIs.avgLoss }
+              { label: "Avg Real-Time LMP ($/MWh)", value: fiveMinKPIs.avgLmp },
+              {
+                label: "Total Real-Time Energy (MWh)",
+                value: fiveMinKPIs.totalEnergy,
+              },
+              {
+                label: "Max Real-Time Congestion ($)",
+                value: fiveMinKPIs.maxCongestion,
+              },
+              { label: "Avg Real-Time Loss ($)", value: fiveMinKPIs.avgLoss },
             ].map((item, idx) => (
               <Col xs={12} md={6} key={idx} style={{ marginBottom: 16 }}>
                 <Card
                   hoverable
                   style={{
-                    textAlign: 'center',
+                    textAlign: "center",
                     borderRadius: 12,
-                    boxShadow: '0 4px 12px rgba(0,0,0,0.05)'
+                    boxShadow: "0 4px 12px rgba(0,0,0,0.05)",
                   }}
                   title={item.label}
                 >
-                  <Typography.Title heading={5}>${item.value.toFixed(2)}</Typography.Title>
+                  <Typography.Title heading={5}>
+                    ${item.value.toFixed(2)}
+                  </Typography.Title>
                 </Card>
               </Col>
             ))}
@@ -226,22 +268,33 @@ function MarketDataPage() {
 
           <Row gutter={24} style={{ marginBottom: 30 }}>
             {[
-              { label: 'Avg Day-Ahead LMP ($/MWh)', value: dayAheadKPIs.avgLmp },
-              { label: 'Total Day-Ahead Energy (MWh)', value: dayAheadKPIs.totalEnergy },
-              { label: 'Max Day-Ahead Congestion ($)', value: dayAheadKPIs.maxCongestion },
-              { label: 'Avg Day-Ahead Loss ($)', value: dayAheadKPIs.avgLoss }
+              {
+                label: "Avg Day-Ahead LMP ($/MWh)",
+                value: dayAheadKPIs.avgLmp,
+              },
+              {
+                label: "Total Day-Ahead Energy (MWh)",
+                value: dayAheadKPIs.totalEnergy,
+              },
+              {
+                label: "Max Day-Ahead Congestion ($)",
+                value: dayAheadKPIs.maxCongestion,
+              },
+              { label: "Avg Day-Ahead Loss ($)", value: dayAheadKPIs.avgLoss },
             ].map((item, idx) => (
               <Col xs={12} md={6} key={idx} style={{ marginBottom: 16 }}>
                 <Card
                   hoverable
                   style={{
-                    textAlign: 'center',
+                    textAlign: "center",
                     borderRadius: 12,
-                    boxShadow: '0 4px 12px rgba(0,0,0,0.05)'
+                    boxShadow: "0 4px 12px rgba(0,0,0,0.05)",
                   }}
                   title={item.label}
                 >
-                  <Typography.Title heading={5}>${item.value.toFixed(2)}</Typography.Title>
+                  <Typography.Title heading={5}>
+                    ${item.value.toFixed(2)}
+                  </Typography.Title>
                 </Card>
               </Col>
             ))}
@@ -249,24 +302,36 @@ function MarketDataPage() {
 
           <Row gutter={24}>
             <Col xs={24} md={12}>
-              <Card title="Real-Time Market Data" extra={<TimeAgo timestamp={fiveMinLastUpdated} prefix="Updated" />} style={{ borderRadius: 12, marginBottom: 24 }}>
+              <Card
+                title="Real-Time Market Data"
+                extra={
+                  <TimeAgo timestamp={fiveMinLastUpdated} prefix="Updated" />
+                }
+                style={{ borderRadius: 12, marginBottom: 24 }}
+              >
                 <div style={{ padding: 10 }}>
                   <VChart
-                                spec={fiveMinSpec}
-                                ref={fiveMinChartRef}
-                                onDataZoom={(e) => handleZoomChange(e.detail, 'fiveMin')}
-                              />
+                    spec={fiveMinSpec}
+                    ref={fiveMinChartRef}
+                    onDataZoom={(e) => handleZoomChange(e.detail, "fiveMin")}
+                  />
                 </div>
               </Card>
             </Col>
             <Col xs={24} md={12}>
-              <Card title="Day-Ahead Market Data" extra={<TimeAgo timestamp={dayAheadLastUpdated} prefix="Updated" />} style={{ borderRadius: 12, marginBottom: 24 }}>
+              <Card
+                title="Day-Ahead Market Data"
+                extra={
+                  <TimeAgo timestamp={dayAheadLastUpdated} prefix="Updated" />
+                }
+                style={{ borderRadius: 12, marginBottom: 24 }}
+              >
                 <div style={{ padding: 10 }}>
                   <VChart
-                                spec={dayAheadSpec}
-                                ref={dayAheadChartRef}
-                                onDataZoom={(e) => handleZoomChange(e.detail, 'dayAhead')}
-                              />
+                    spec={dayAheadSpec}
+                    ref={dayAheadChartRef}
+                    onDataZoom={(e) => handleZoomChange(e.detail, "dayAhead")}
+                  />
                 </div>
               </Card>
             </Col>
-- 
cgit v1.2.3

