aboutsummaryrefslogtreecommitdiff
path: root/client/src/App.js
blob: d130e08ccc9a9e9dd094d10dc8f182312ad2a249 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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;