aboutsummaryrefslogtreecommitdiff
path: root/client/src/MarketDataPage.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/MarketDataPage.jsx')
-rw-r--r--client/src/MarketDataPage.jsx141
1 files changed, 82 insertions, 59 deletions
diff --git a/client/src/MarketDataPage.jsx b/client/src/MarketDataPage.jsx
index 3ffa099..76d8284 100644
--- a/client/src/MarketDataPage.jsx
+++ b/client/src/MarketDataPage.jsx
@@ -1,73 +1,99 @@
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useState, useContext } 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';
+
const { Row, Col } = Grid;
-function MarketDataPage() {
- const [fiveMinData, setFiveMinData] = useState([]);
- const [dayAheadData, setDayAheadData] = useState([]);
- const [loading, setLoading] = useState(true);
- const [fiveMinLastUpdated, setFiveMinLastUpdated] = useState(null);
- const [dayAheadLastUpdated, setDayAheadLastUpdated] = useState(null);
+function TimeAgo({ timestamp, prefix }) {
const [now, setNow] = useState(new Date());
useEffect(() => {
- const fetchFiveMinData = async () => {
- try {
- const res = await fetch(`${API_BASE_URL}/market/real-time`);
- 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.');
- }
- };
+ const timer = setInterval(() => setNow(new Date()), 1000);
+ return () => clearInterval(timer);
+ }, []);
- const fetchDayAheadData = async () => {
- try {
- const res = await fetch(`${API_BASE_URL}/market/day-ahead`);
- 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.');
- }
- };
+ const formatTimeAgo = () => {
+ if (!timestamp) return '';
+ const seconds = Math.floor((now - timestamp) / 1000);
+ if (seconds < 60) return `${seconds} sec ago`;
+ const minutes = Math.floor(seconds / 60);
+ if (minutes < 60) return `${minutes} min ago`;
+ const hours = Math.floor(minutes / 60);
+ return `${hours} hr ago`;
+ };
- const initialize = async () => {
- setLoading(true);
- await Promise.all([fetchFiveMinData(), fetchDayAheadData()]);
- setLoading(false);
+ return (
+ <Typography.Text type="secondary" style={{ display: 'block' }}>
+ {prefix}: {formatTimeAgo()}
+ </Typography.Text>
+ );
+}
- initVChartArcoTheme({
- defaultMode: 'light',
- isWatchingMode: true
- });
- };
- initialize();
+function MarketDataPage() {
+ const { selectedMarket } = useContext(MarketContext);
+ const [fiveMinData, setFiveMinData] = useState([]);
+ const [dayAheadData, setDayAheadData] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [fiveMinLastUpdated, setFiveMinLastUpdated] = useState(null);
+ const [dayAheadLastUpdated, setDayAheadLastUpdated] = useState(null);
+ const [now, setNow] = useState(new Date());
+
+ 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 json = await res.json();
+ setFiveMinData(json);
+ setFiveMinLastUpdated(new Date());
+ } catch (err) {
+ console.error(err);
+ 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 json = await res.json();
+ setDayAheadData(json);
+ setDayAheadLastUpdated(new Date());
+ } catch (err) {
+ console.error(err);
+ Message.error('Failed to load day-ahead market data.');
+ }
+ };
- const fiveMinInterval = setInterval(fetchFiveMinData, 5 * 60 * 1000); // 5 minutes
- const dayAheadInterval = setInterval(fetchDayAheadData, 60 * 60 * 1000); // 1 hour
+ const initialize = async () => {
+ setLoading(true);
+ await Promise.all([fetchFiveMinData(), fetchDayAheadData()]);
+ setLoading(false);
- const timer = setInterval(() => {
- setNow(new Date());
- }, 1000);
+ initVChartArcoTheme({
+ defaultMode: 'light',
+ isWatchingMode: true
+ });
+ };
- return () => {
- clearInterval(fiveMinInterval);
- clearInterval(dayAheadInterval);
- clearInterval(timer);
- };
- }, []);
+ initialize();
+
+ const fiveMinInterval = setInterval(fetchFiveMinData, 5 * 60 * 1000); // 5 minutes
+ const dayAheadInterval = setInterval(fetchDayAheadData, 60 * 60 * 1000); // 1 hour
+ const timer = setInterval(() => setNow(new Date()), 1000);
+
+ return () => {
+ clearInterval(fiveMinInterval);
+ clearInterval(dayAheadInterval);
+ clearInterval(timer);
+ };
+ }, [selectedMarket]);
const getChartSpec = (data, title) => ({
type: 'line',
@@ -151,18 +177,15 @@ function MarketDataPage() {
return (
<div style={{ padding: 20, backgroundColor: 'var(--color-fill-2)' }}>
- <Typography.Title heading={4}>Market Data Visualization</Typography.Title>
- <Typography.Text type="secondary" style={{ marginTop: 10, display: 'block' }}>
- Real-Time Data Last Updated: {formatTimeAgo(fiveMinLastUpdated)}
- </Typography.Text>
- <Typography.Text type="secondary" style={{ marginBottom: 20, display: 'block' }}>
- Day-Ahead Data Last Updated: {formatTimeAgo(dayAheadLastUpdated)}
- </Typography.Text>
+ <Typography.Title heading={4}>Market Data for {MARKET_FULL_NAMES[selectedMarket]}</Typography.Title>
+
{loading ? (
<Spin />
) : (
<>
+ <TimeAgo timestamp={fiveMinLastUpdated} prefix="Real-Time Data Last Updated" />
+ <TimeAgo timestamp={dayAheadLastUpdated} prefix="Day-Ahead Data Last Updated" />
<Row gutter={24} style={{ marginTop: 20, marginBottom: 20 }}>
<Col xs={12} md={6} style={{ marginTop: 10}}>
<Card style={{ textAlign: 'center' }} title="Avg Real-Time LMP ($/MWh)">