added the sites page and all other required imports for it to work, also fixed the map card
This commit is contained in:
parent
c5afdc2c3d
commit
3990dfbf4f
14 changed files with 1595 additions and 21 deletions
409
src/objectHeater/ObjectHeaterCard.tsx
Normal file
409
src/objectHeater/ObjectHeaterCard.tsx
Normal file
|
|
@ -0,0 +1,409 @@
|
|||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
CardContent,
|
||||
Grid2 as Grid,
|
||||
ListItemAvatar,
|
||||
ListItemText,
|
||||
Theme,
|
||||
Typography,
|
||||
useTheme
|
||||
} from "@mui/material";
|
||||
import { GetDefaultDateRange } from "common/time/DateRange";
|
||||
import UnitMeasurementSummary from "component/UnitMeasurementSummary";
|
||||
import { useThemeType } from "hooks";
|
||||
import { Component, Device } from "models";
|
||||
import { ObjectHeater } from "models/ObjectHeater";
|
||||
import { UnitMeasurement } from "models/UnitMeasurement";
|
||||
import moment from "moment";
|
||||
import { GetComponentIcon } from "pbHelpers/ComponentType";
|
||||
import ObjectHeaterIcon from "products/Construction/ObjectHeaterIcon";
|
||||
import { pond, quack } from "protobuf-ts/pond";
|
||||
import { useGlobalState, useMutationAPI } from "providers";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import FuelDark from "assets/components/fuelDark.png";
|
||||
import FuelLight from "assets/components/fuelLight.png";
|
||||
//import { useHistory } from "react-router";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import Link from "@mui/icons-material/Link";
|
||||
import EventBlocker from "common/EventBlocker";
|
||||
import { GetDeviceProductIcon } from "products/DeviceProduct";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
|
||||
interface Props {
|
||||
heaterData: pond.ObjectHeaterData;
|
||||
linkDevice: (heater: ObjectHeater, linkedDevices: pond.ComprehensiveDevice[]) => void;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
avatarIcon: {
|
||||
width: theme.spacing(3),
|
||||
height: theme.spacing(3)
|
||||
},
|
||||
listAvatar: {
|
||||
minWidth: theme.spacing(5)
|
||||
},
|
||||
avatarImage: {
|
||||
width: theme.spacing(3),
|
||||
height: theme.spacing(3)
|
||||
},
|
||||
textOverflow: {
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
textTransform: "capitalize"
|
||||
},
|
||||
listText: {
|
||||
margin: 0,
|
||||
height: "100%"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
export default function ObjectHeaterCard(props: Props) {
|
||||
const { heaterData, linkDevice } = props;
|
||||
const [heater, setHeater] = useState<ObjectHeater>(ObjectHeater.create());
|
||||
const [connectedDevice, setConnectedDevice] = useState<Device>();
|
||||
const mutationAPI = useMutationAPI();
|
||||
const [heaterComponent, setHeaterComponent] = useState<Component>();
|
||||
const [heaterTempComponent, setHeaterTempComponent] = useState<Component>();
|
||||
const [siteTempComponent, setSiteTempComponent] = useState<Component>();
|
||||
const [mutationsLoading, setMutationsLoading] = useState(false);
|
||||
const classes = useStyles();
|
||||
const themeType = useThemeType();
|
||||
const [{ user }] = useGlobalState();
|
||||
const [lastFuelCalc, setLastFuelCalc] = useState<pond.ValueAt>();
|
||||
const [lastFuelMutation, setLastFuelMutation] = useState<pond.LinearMutation>();
|
||||
const [allComponentsRecent, setAllComponentsRecent] = useState(true);
|
||||
//const history = useHistory();
|
||||
const navigate = useNavigate();
|
||||
const theme = useTheme();
|
||||
|
||||
useEffect(() => {
|
||||
let heater = ObjectHeater.any(heaterData.heater);
|
||||
setHeater(heater);
|
||||
if (!mutationsLoading && heater) {
|
||||
let fuelMutation: pond.LinearMutation | undefined;
|
||||
heater.settings.mutations.forEach(mutation => {
|
||||
if (mutation.mutation === pond.Mutator.MUTATOR_FUEL_LEVEL) {
|
||||
fuelMutation = mutation;
|
||||
}
|
||||
});
|
||||
if (fuelMutation !== undefined) {
|
||||
mutationAPI
|
||||
.linearMutation(
|
||||
fuelMutation,
|
||||
GetDefaultDateRange()
|
||||
.end.add(-1, "hour")
|
||||
.toISOString(),
|
||||
GetDefaultDateRange().end.toISOString()
|
||||
)
|
||||
.then(resp => {
|
||||
resp.data.values.forEach(val => {
|
||||
setLastFuelCalc(val);
|
||||
});
|
||||
setLastFuelMutation(fuelMutation);
|
||||
setMutationsLoading(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (heaterData.devices[0]) {
|
||||
setConnectedDevice(Device.any(heaterData.devices[0].device));
|
||||
heaterData.devices[0].components.forEach(c => {
|
||||
//loop through the components and assign them accordingly
|
||||
let component = Component.any(c);
|
||||
if (
|
||||
component.type() === quack.ComponentType.COMPONENT_TYPE_BOOLEAN_OUTPUT &&
|
||||
component.subType() === quack.BooleanOutputSubtype.BOOLEAN_OUTPUT_SUBTYPE_HEATER
|
||||
) {
|
||||
setHeaterComponent(component);
|
||||
component.lastMeasurement.forEach(um => {
|
||||
if (
|
||||
um.timestamps.length > 0 &&
|
||||
um.type === quack.MeasurementType.MEASUREMENT_TYPE_BOOLEAN
|
||||
) {
|
||||
if (
|
||||
moment().diff(moment(um.timestamps[0]), "milliseconds") >
|
||||
component.settings.reportPeriodMs
|
||||
) {
|
||||
setAllComponentsRecent(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (component.type() === quack.ComponentType.COMPONENT_TYPE_TEMPERATURE) {
|
||||
setHeaterTempComponent(component);
|
||||
component.lastMeasurement.forEach(um => {
|
||||
if (
|
||||
um.timestamps.length > 0 &&
|
||||
um.type === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE
|
||||
) {
|
||||
if (
|
||||
moment().diff(moment(um.timestamps[0]), "milliseconds") >
|
||||
component.settings.reportPeriodMs
|
||||
) {
|
||||
setAllComponentsRecent(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (component.type() === quack.ComponentType.COMPONENT_TYPE_DHT) {
|
||||
setSiteTempComponent(component);
|
||||
component.lastMeasurement.forEach(um => {
|
||||
if (
|
||||
um.timestamps.length > 0 &&
|
||||
um.type === quack.MeasurementType.MEASUREMENT_TYPE_BOOLEAN
|
||||
) {
|
||||
if (
|
||||
moment().diff(moment(um.timestamps[0]), "milliseconds") >
|
||||
component.settings.reportPeriodMs
|
||||
) {
|
||||
setAllComponentsRecent(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [heaterData, mutationAPI]); //eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const goToHeater = () => {
|
||||
//history.push("/objectHeaters/" + heater.key);
|
||||
let path = "/objectHeaters/" + heater.key;
|
||||
navigate(path, { state: {heater: heater} });
|
||||
};
|
||||
|
||||
const componentDisplay = (component?: Component) => {
|
||||
return (
|
||||
<Grid container direction="row" wrap="nowrap" alignContent="center" alignItems="center">
|
||||
{component ? (
|
||||
<React.Fragment>
|
||||
<Grid>
|
||||
<Avatar
|
||||
variant="square"
|
||||
alt="icon"
|
||||
src={GetComponentIcon(component.type(), component.subType(), themeType)}
|
||||
style={{ float: "left" }}
|
||||
className={classes.avatarIcon}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid style={{ paddingLeft: 5 }}>
|
||||
<UnitMeasurementSummary
|
||||
component={component}
|
||||
reading={UnitMeasurement.convertLastMeasurement(
|
||||
component.lastMeasurement.map(um => UnitMeasurement.any(um, user))
|
||||
)}
|
||||
omitTime
|
||||
dense
|
||||
centered
|
||||
onlyRecent
|
||||
/>
|
||||
</Grid>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
"Component Not Found"
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
//// TODO-CS: Make a mutator describer to put the get functions into ////
|
||||
const getMutationIcon = (mutation: pond.Mutator, themeType: string) => {
|
||||
if (mutation === pond.Mutator.MUTATOR_FUEL_LEVEL) {
|
||||
return themeType === "light" ? FuelDark : FuelLight;
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
const getMutationColour = (mutation: pond.Mutator) => {
|
||||
if (mutation === pond.Mutator.MUTATOR_FUEL_LEVEL) {
|
||||
return "lightBlue";
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
const getMutationUnit = (mutation: pond.Mutator) => {
|
||||
if (mutation === pond.Mutator.MUTATOR_FUEL_LEVEL) {
|
||||
return "%";
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
//// /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ /\ ////
|
||||
|
||||
const fuelMutationDisplay = () => {
|
||||
if (!lastFuelMutation) {
|
||||
return (
|
||||
<Grid container direction="row" wrap="nowrap" alignContent="center" alignItems="center">
|
||||
{/* <Grid item>
|
||||
<Avatar
|
||||
variant="square"
|
||||
alt="icon"
|
||||
src={getMutationIcon(pond.Mutator.MUTATOR_FUEL_LEVEL, themeType)}
|
||||
style={{ float: "left" }}
|
||||
className={classes.avatarIcon}
|
||||
/>
|
||||
</Grid> */}
|
||||
<Grid style={{ paddingLeft: 5 }}>
|
||||
N/A
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
if (lastFuelCalc) {
|
||||
return (
|
||||
<Grid container>
|
||||
<Grid>
|
||||
<Avatar
|
||||
variant="square"
|
||||
alt="icon"
|
||||
src={getMutationIcon(pond.Mutator.MUTATOR_FUEL_LEVEL, themeType)}
|
||||
style={{ float: "left" }}
|
||||
className={classes.avatarIcon}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid style={{ paddingLeft: 5 }}>
|
||||
<Typography variant="caption" color="textPrimary">
|
||||
<span>
|
||||
<span style={{ color: getMutationColour(pond.Mutator.MUTATOR_FUEL_LEVEL) }}>
|
||||
{(lastFuelCalc.value / 10).toFixed(2) +
|
||||
getMutationUnit(pond.Mutator.MUTATOR_FUEL_LEVEL)}
|
||||
</span>
|
||||
</span>
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Grid container direction="row" wrap="nowrap" alignContent="center" alignItems="center">
|
||||
<Grid>
|
||||
<Avatar
|
||||
variant="square"
|
||||
alt="icon"
|
||||
src={getMutationIcon(pond.Mutator.MUTATOR_FUEL_LEVEL, themeType)}
|
||||
style={{ float: "left" }}
|
||||
className={classes.avatarIcon}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid style={{ paddingLeft: 5 }}>
|
||||
No Recent Data
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
//content of the card of there is no device linked to the heater
|
||||
const unlinkedCard = () => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<CardContent style={{ paddingLeft: 30, paddingRight: 30 }}>
|
||||
<Grid
|
||||
container
|
||||
direction="row"
|
||||
alignContent="center"
|
||||
alignItems="center">
|
||||
<Grid size={4}>
|
||||
<EventBlocker>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
linkDevice(heater, heaterData.devices);
|
||||
}}>
|
||||
<Link />
|
||||
</Button>
|
||||
</EventBlocker>
|
||||
</Grid>
|
||||
<Grid size={7}>
|
||||
<Typography>{heater.name}</Typography>
|
||||
</Grid>
|
||||
<Grid size={1}>
|
||||
<ObjectHeaterIcon />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
//content of the card if a device is linked to the heater
|
||||
const linkedCard = (device: Device) => {
|
||||
const productIcon = GetDeviceProductIcon(device);
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Box height="100%" display="flex" alignItems="center" flexWrap="nowrap" padding={2}>
|
||||
<ListItemAvatar className={classes.listAvatar}>
|
||||
<Avatar
|
||||
variant="square"
|
||||
src={productIcon}
|
||||
className={classes.avatarImage}
|
||||
alt="product"
|
||||
/>
|
||||
</ListItemAvatar>
|
||||
<Grid container direction="column">
|
||||
<Grid>
|
||||
<ListItemText
|
||||
primary={heater.name}
|
||||
primaryTypographyProps={{
|
||||
className: classes.textOverflow,
|
||||
variant: "subtitle1"
|
||||
}}
|
||||
className={classes.listText}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<ListItemText
|
||||
primary={"Device: " + device.id()}
|
||||
primaryTypographyProps={{
|
||||
className: classes.textOverflow,
|
||||
variant: "subtitle2"
|
||||
}}
|
||||
className={classes.listText}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<ListItemText
|
||||
primary={"Last Checked In: " + moment(device.status.lastActive).fromNow()}
|
||||
primaryTypographyProps={{
|
||||
className: classes.textOverflow,
|
||||
variant: "subtitle2"
|
||||
}}
|
||||
className={classes.listText}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
{allComponentsRecent ? (
|
||||
<CardContent>
|
||||
<Grid
|
||||
container
|
||||
direction="row"
|
||||
alignContent="center"
|
||||
alignItems="center">
|
||||
<Grid>{componentDisplay(heaterComponent)}</Grid>
|
||||
<Grid>{componentDisplay(heaterTempComponent)}</Grid>
|
||||
<Grid>{componentDisplay(siteTempComponent)}</Grid>
|
||||
<Grid>{fuelMutationDisplay()}</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
) : (
|
||||
<Box
|
||||
display="flex"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
style={{ backgroundColor: "orange", padding: 10, borderRadius: "0px 0px 10px 10px" }}>
|
||||
A Component Is Not Reporting
|
||||
</Box>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Card raised onClick={goToHeater} style={{ margin: 5 }}>
|
||||
{connectedDevice ? linkedCard(connectedDevice) : unlinkedCard()}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue