Genesis
This commit is contained in:
92
src/client/ControllerCard.js
Normal file
92
src/client/ControllerCard.js
Normal file
@@ -0,0 +1,92 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Card, CardHeader, CardContent, Divider, Grid, Box, Typography } from '@mui/material';
|
||||
import EnvChart from './EnvChart';
|
||||
import LevelChart from './LevelChart';
|
||||
|
||||
export default function ControllerCard({ controllerName, ports, range }) {
|
||||
const [envData, setEnvData] = useState([]);
|
||||
const [portData, setPortData] = useState({});
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
if (ports.length === 0) return;
|
||||
|
||||
// Fetch all ports concurrently
|
||||
const promises = ports.map(port =>
|
||||
fetch(`api/history?devName=${encodeURIComponent(controllerName)}&port=${port.port}&range=${range}`)
|
||||
.then(res => res.json())
|
||||
.then(data => ({ port: port.port, data }))
|
||||
);
|
||||
|
||||
const results = await Promise.all(promises);
|
||||
|
||||
const newPortData = {};
|
||||
results.forEach(item => {
|
||||
newPortData[item.port] = item.data;
|
||||
});
|
||||
|
||||
setPortData(newPortData);
|
||||
|
||||
// Use the data from the first port for the Environment Chart
|
||||
// This avoids a redundant network request
|
||||
if (results.length > 0) {
|
||||
setEnvData(results[0].data);
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error("Fetch error", err);
|
||||
}
|
||||
};
|
||||
|
||||
// Initial Fetch & Auto-Refresh
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
const interval = setInterval(fetchData, 60000);
|
||||
return () => clearInterval(interval);
|
||||
}, [controllerName, range]); // Depend on range, controllerName changes rarely
|
||||
|
||||
return (
|
||||
<Card sx={{ mb: 4, borderRadius: 2, boxShadow: 3 }}>
|
||||
<CardHeader
|
||||
title={controllerName}
|
||||
titleTypographyProps={{ variant: 'h5', fontWeight: 'bold', color: 'primary.main' }}
|
||||
sx={{ bgcolor: 'background.paper', borderLeft: '6px solid', borderLeftColor: 'primary.main' }}
|
||||
/>
|
||||
<CardContent>
|
||||
{/* Environment Chart */}
|
||||
<Box sx={{ height: 350, mb: 6 }}>
|
||||
<Typography variant="h6" color="text.secondary" gutterBottom>
|
||||
Environment (Temp / Humidity)
|
||||
</Typography>
|
||||
<EnvChart data={envData} range={range} />
|
||||
</Box>
|
||||
|
||||
<Divider sx={{ mt: 2, mb: 3 }} />
|
||||
|
||||
{/* Port Grid */}
|
||||
<Grid container spacing={3}>
|
||||
{ports.map((port) => {
|
||||
const isLight = port.port_name && port.port_name.toLowerCase().includes('light');
|
||||
const isCO2 = port.port_name && port.port_name.toLowerCase().includes('co2');
|
||||
const pData = portData[port.port] || [];
|
||||
|
||||
return (
|
||||
<Grid size={{ xs: 12, md: 6, lg: 4 }} key={port.port}>
|
||||
<Card variant="outlined" sx={{ bgcolor: 'background.paper' }}>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
{port.port_name || `Port ${port.port}`}
|
||||
</Typography>
|
||||
<Box sx={{ height: 250 }}>
|
||||
<LevelChart data={pData} isLight={isLight} isCO2={isCO2} range={range} />
|
||||
</Box>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user