104 lines
No EOL
4.7 KiB
TypeScript
104 lines
No EOL
4.7 KiB
TypeScript
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>
|
|
)
|
|
} |