finished the bin sensor view to display connected components for a bin

This commit is contained in:
csawatzky 2026-05-28 11:18:40 -06:00
parent 67b251d865
commit b00f10b831
16 changed files with 983 additions and 232 deletions

105
src/bin/BinSensorCard.tsx Normal file
View file

@ -0,0 +1,105 @@
import { AccessTime, MoreVert } from "@mui/icons-material";
import { Avatar, Box, Card, IconButton, Table, TableBody, TableCell, TableHead, TableRow, Typography, useTheme } from "@mui/material";
import moment from "moment";
import React from "react";
interface SensorRow {
label: string;
data: string;
}
interface CableRow {
label: string;
min: string;
avg: string;
max: string;
}
interface Props {
name: string;
icon?: string;
tag: string;
lastReading: string;
onMenuClick: (event: React.MouseEvent<HTMLButtonElement>) => void;
rows?: SensorRow[];
cableRows?: CableRow[];
/**
* the time in hours that a reading is considered 'good'
* defaults to 6
*/
staleLimit?: number;
}
export default function BinSensorCard(props: Props) {
const { name, icon, tag, lastReading, onMenuClick, rows, cableRows, staleLimit = 6 } = props
const theme = useTheme()
const isStale = moment().diff(moment(lastReading), "hours") > staleLimit
return (
<Card raised sx={{ height: "100%" }}>
<Box padding={1.5} height="100%" display="flex" flexDirection="column">
<Box display="flex" justifyContent="space-between" alignItems="center" marginBottom={1}>
<Box display="flex" alignItems="center" gap={1}>
{icon &&
<Avatar
variant="square"
src={icon}
alt={name + " icon"}
style={{ width: theme.spacing(3), height: theme.spacing(3) }}
/>
}
<Typography fontWeight={500}>{name}</Typography>
<Typography variant="caption" color="textSecondary">- {tag}</Typography>
</Box>
<IconButton size="small" onClick={onMenuClick}>
<MoreVert fontSize="small" />
</IconButton>
</Box>
<Table size="small">
{cableRows ? (
<>
<TableHead>
<TableRow>
<TableCell sx={{ color: "text.secondary", fontSize: 11, fontWeight: 500, border: 0, pb: 0.5, pl: 0 }} />
<TableCell align="right" sx={{ color: "text.secondary", fontSize: 11, fontWeight: 500, border: 0, pb: 0.5 }}>Min</TableCell>
<TableCell align="right" sx={{ color: "primary.main", fontSize: 11, fontWeight: 500, border: 0, pb: 0.5 }}>Avg</TableCell>
<TableCell align="right" sx={{ color: "text.secondary", fontSize: 11, fontWeight: 500, border: 0, pb: 0.5, pr: 0 }}>Max</TableCell>
</TableRow>
</TableHead>
<TableBody>
{cableRows.map((row) => (
<TableRow key={row.label}>
<TableCell sx={{ color: "text.secondary", fontSize: 11, pl: 0, py: 0.5 }}>{row.label}</TableCell>
<TableCell align="right" sx={{ fontSize: 12, py: 0.5 }}>{row.min}</TableCell>
<TableCell align="right" sx={{ color: "primary.main", fontWeight: 500, fontSize: 12, py: 0.5 }}>{row.avg}</TableCell>
<TableCell align="right" sx={{ fontSize: 12, py: 0.5, pr: 0 }}>{row.max}</TableCell>
</TableRow>
))}
</TableBody>
</>
) : (
<TableBody>
{rows?.map((row) => (
<TableRow key={row.label}>
<TableCell sx={{ color: "text.secondary", fontSize: 11, pl: 0, py: 0.5 }}>{row.label}</TableCell>
<TableCell align="right" sx={{ fontSize: 12, py: 0.5 }}>{row.data}</TableCell>
</TableRow>
))}
</TableBody>
)}
</Table>
<Box display="flex" alignItems="center" gap={0.5} marginTop="auto">
<AccessTime sx={{ fontSize: 12, color: isStale ? "warning.main" : "text.disabled" }} />
<Typography variant="caption" color={isStale ? "warning.main" : "text.secondary"}>
{moment(lastReading).fromNow()}
</Typography>
</Box>
</Box>
</Card>
)
}