88 lines
3.3 KiB
JavaScript
88 lines
3.3 KiB
JavaScript
import React, { useState, useEffect, useCallback } from 'react';
|
|
import { Grid, Typography, Button, ButtonGroup, Box, Alert } from '@mui/material';
|
|
import ControllerCard from './ControllerCard';
|
|
import { useI18n } from './I18nContext';
|
|
|
|
export default function Dashboard() {
|
|
const { t } = useI18n();
|
|
const [groupedDevices, setGroupedDevices] = useState({});
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState(null);
|
|
const [range, setRange] = useState('day'); // 'day', 'week', 'month'
|
|
|
|
const fetchDevices = useCallback(async () => {
|
|
try {
|
|
// Robust API Base detection
|
|
const baseUrl = window.location.pathname.endsWith('/') ? 'api/' : 'api/';
|
|
// Actually, since we are serving from root or subpath, relative 'api/' is tricky if URL depth changes.
|
|
// Better to use a relative path that works from the page root.
|
|
// If page is /ac-dashboard/, fetch is /ac-dashboard/api/devices.
|
|
|
|
const res = await fetch('api/devices');
|
|
if (!res.ok) throw new Error('Failed to fetch devices');
|
|
|
|
const devices = await res.json();
|
|
|
|
// Group by dev_name
|
|
const grouped = devices.reduce((acc, dev) => {
|
|
if (!acc[dev.dev_name]) acc[dev.dev_name] = [];
|
|
acc[dev.dev_name].push(dev);
|
|
return acc;
|
|
}, {});
|
|
|
|
setGroupedDevices(grouped);
|
|
setLoading(false);
|
|
} catch (err) {
|
|
console.error(err);
|
|
setError(err.message);
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
fetchDevices();
|
|
}, [fetchDevices]);
|
|
|
|
// Auto-refresh logic (basic rerender trigger could be added here,
|
|
// but simpler to let ControllerCard handle data fetching internally based on props)
|
|
|
|
if (loading) return <Typography>{t('dashboard.loading')}</Typography>;
|
|
if (error) return <Alert severity="error">{error}</Alert>;
|
|
|
|
return (
|
|
<Box>
|
|
<Box display="flex" justifyContent="flex-end" mb={3}>
|
|
<ButtonGroup variant="contained" aria-label="outlined primary button group">
|
|
<Button
|
|
onClick={() => setRange('day')}
|
|
color={range === 'day' ? 'primary' : 'inherit'}
|
|
>
|
|
{t('dashboard.hours24')}
|
|
</Button>
|
|
<Button
|
|
onClick={() => setRange('week')}
|
|
color={range === 'week' ? 'primary' : 'inherit'}
|
|
>
|
|
{t('dashboard.days7')}
|
|
</Button>
|
|
<Button
|
|
onClick={() => setRange('month')}
|
|
color={range === 'month' ? 'primary' : 'inherit'}
|
|
>
|
|
{t('dashboard.days30')}
|
|
</Button>
|
|
</ButtonGroup>
|
|
</Box>
|
|
|
|
{Object.entries(groupedDevices).map(([controllerName, ports]) => (
|
|
<ControllerCard
|
|
key={controllerName}
|
|
controllerName={controllerName}
|
|
ports={ports}
|
|
range={range}
|
|
/>
|
|
))}
|
|
</Box>
|
|
);
|
|
}
|