diff options
Diffstat (limited to 'client/src/App.js')
-rw-r--r-- | client/src/App.js | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/client/src/App.js b/client/src/App.js new file mode 100644 index 0000000..d130e08 --- /dev/null +++ b/client/src/App.js @@ -0,0 +1,122 @@ +import React, { useEffect, useState } from 'react'; +import { Typography, Spin, Message, Card, Grid, PageHeader } from '@arco-design/web-react'; +import '@arco-design/web-react/dist/css/arco.css'; +import { VChart } from '@visactor/react-vchart'; + +const { Row, Col } = Grid; +const ghostBgStyle = { + backgroundImage: 'radial-gradient(var(--color-fill-3) 1px, rgba(0, 0, 0, 0) 1px)', + backgroundSize: '16px 16px', + padding: 20, +}; + +function App() { + const [fiveMinData, setFiveMinData] = useState([]); + const [dayAheadData, setDayAheadData] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + Promise.all([ + fetch('http://127.0.0.1:8000/market/real-time'), + fetch('http://127.0.0.1:8000/market/day-ahead') + ]) + .then(async ([res1, res2]) => { + if (!res1.ok || !res2.ok) throw new Error('Failed to fetch data'); + const json1 = await res1.json(); + const json2 = await res2.json(); + setFiveMinData(json1); + setDayAheadData(json2); + }) + .catch((err) => { + console.error(err); + Message.error('Failed to load market data.'); + }) + .finally(() => setLoading(false)); + }, []); + + const getChartSpec = (data, title) => ({ + type: 'line', + data: { + values: data.map(d => ({ + timestamp: new Date(d.timestamp).toLocaleString(), + lmp: d.lmp, + energy: d.energy, + congestion: d.congestion, + loss: d.loss + })), + transforms: [ + { + type: 'fold', + options: { + key: 'name', + value: 'value', + fields: ['lmp', 'energy', 'congestion', 'loss'] + } + } + ] + }, + xField: 'timestamp', + yField: 'value', + seriesField: 'name', + smooth: true, + legend: { + position: 'top' + }, + tooltip: { + formatter: (datum) => ({ + name: datum.name, + value: datum.value.toFixed(2) + }) + }, + dataZoom: [ + { + orient: 'bottom', + height: 20, + start: title === 'fiveMin' ? 0.9 : 0.05, + end: 1 + } + ] + }); + + return ( + <> + <div style={ghostBgStyle}> + <PageHeader title={ + <Typography.Title heading={3}>PolyEnergy</Typography.Title> + } subTitle={ + <Typography.Title type="secondary" heading={4}>Virtual Energy Trading</Typography.Title> + } /> + </div> + <div style={{ padding: 20, backgroundColor: 'var(--color-fill-2)' }}> + <Typography.Title heading={4}>Market Data Visualization</Typography.Title> + {loading ? ( + <Spin /> + ) : ( + <> + <div + style={{ + width: '100%', + backgroundColor: 'var(--color-fill-2)', + }} + > + <Row gutter={24}> + <Col span={12}> + <Card style={{ height: 600}} title='Real-Time Market Data'> + <VChart spec={getChartSpec(fiveMinData, 'fiveMin')} /> + </Card> + </Col> + <Col span={12}> + <Card style={{ height: 600}} title='Day-Ahead Market Data'> + <VChart spec={getChartSpec(dayAheadData, 'dayAhead')} /> + </Card> + </Col> + </Row> + </div> + </> + )} + </div> + </> + ); +} + +export default App; |