247 lines
8.4 KiB
TypeScript
247 lines
8.4 KiB
TypeScript
import { Chip, Grid2 as Grid, Theme, Tooltip, Skeleton } from "@mui/material";
|
|
import { DataUsage, SimCard, Launch } from "@mui/icons-material";
|
|
import StatusChip from "common/StatusChip";
|
|
import DeviceTags from "device/DeviceTags";
|
|
import VersionChip from "device/VersionChip";
|
|
import { useSnackbar, useWidth, usePrevious } from "hooks";
|
|
import { Device, latestFirmwareVersion, Component } from "models";
|
|
import moment from "moment";
|
|
import { describeConnectivity } from "pbHelpers/Connectivity";
|
|
import { describePower } from "pbHelpers/Power";
|
|
import { pond, quack } from "protobuf-ts/pond";
|
|
import { useGlobalState } from "providers";
|
|
import React, { useEffect, useState } from "react";
|
|
// import { useHistory, useRouteMatch } from "react-router";
|
|
import { notNull, or } from "utils/types";
|
|
// import { MatchParams } from "navigation/Routes";
|
|
// import DeviceHologram from "./DeviceHologram";
|
|
import { makeStyles } from "@mui/styles";
|
|
import { useNavigate } from "react-router-dom";
|
|
|
|
const useStyles = makeStyles((_theme: Theme) => {
|
|
return ({
|
|
chipContainer: {
|
|
position: "relative",
|
|
maxWidth: "100%",
|
|
overflowX: "auto"
|
|
}
|
|
})
|
|
});
|
|
|
|
interface Usage {
|
|
status: string;
|
|
bytes: number;
|
|
}
|
|
|
|
interface Props {
|
|
device: Device;
|
|
components: Component[];
|
|
usage?: Usage;
|
|
loading?: boolean;
|
|
disableAddTag?: boolean;
|
|
groupID?: number;
|
|
}
|
|
|
|
export default function DeviceOverview(props: Props) {
|
|
const [{ user, firmware }] = useGlobalState();
|
|
const { device, components, groupID, usage, loading, disableAddTag } = props;
|
|
const prevComponents = usePrevious(components);
|
|
const { info } = useSnackbar();
|
|
const classes = useStyles();
|
|
const width = useWidth();
|
|
const now = moment();
|
|
const navigate = useNavigate();
|
|
// const match = useRouteMatch<MatchParams>();
|
|
const [powerComponent, setPowerComponent] = useState<Component | undefined | null>();
|
|
const [modemComponent, setModemComponent] = useState<Component | undefined | null>();
|
|
// const [hologramDialog, setHologramDialog] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (components !== prevComponents) {
|
|
let updatedPower = null;
|
|
let updatedModem = null;
|
|
components.forEach(c => {
|
|
switch (c.settings.type) {
|
|
case quack.ComponentType.COMPONENT_TYPE_POWER:
|
|
updatedPower = c;
|
|
break;
|
|
case quack.ComponentType.COMPONENT_TYPE_MODEM:
|
|
updatedModem = c;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
});
|
|
setPowerComponent(updatedPower);
|
|
setModemComponent(updatedModem);
|
|
}
|
|
}, [components, prevComponents]);
|
|
|
|
const pathToDevice = () => {
|
|
if (groupID) {
|
|
const groupPath: string = groupID > 0 ? "/groups/" + groupID.toString() : "";
|
|
const devicePath: string = "/devices/" + device.settings.deviceId.toString();
|
|
return groupPath + devicePath;
|
|
}
|
|
// const groupID = parseInt(useParams().groupID ?? "0", 10);
|
|
// console.log(groupID)
|
|
// const groupID: number = parseInt(match.params.groupID, 10);
|
|
// const groupPath: string = groupID > 0 ? "/groups/" + groupID.toString() : "";
|
|
const devicePath: string = "/devices/" + device.settings.deviceId.toString();
|
|
return devicePath;
|
|
};
|
|
|
|
const copySim = (sim: string) => {
|
|
navigator.clipboard.writeText(sim);
|
|
info("SIM copied to clipboard");
|
|
};
|
|
|
|
const chips = () => {
|
|
const currentVersion = device.status.firmwareVersion;
|
|
const hasVersion: boolean = currentVersion && currentVersion !== "" ? true : false;
|
|
const connectivity = describeConnectivity(
|
|
device.settings.platform,
|
|
device.status.lastActive,
|
|
device.settings.pondCheckPeriodS,
|
|
now
|
|
);
|
|
const latestFirmware = latestFirmwareVersion(
|
|
firmware,
|
|
device.settings.platform,
|
|
device.settings.upgradeChannel
|
|
);
|
|
const power = describePower(
|
|
pond.DevicePower.create(device.status.power ? device.status.power : undefined)
|
|
);
|
|
const iccid = device.status.sim;
|
|
let usageDesc = "";
|
|
if (usage && isNaN(usage.bytes)) {
|
|
usageDesc = "0 B";
|
|
} else if (usage && usage.bytes < 1000) {
|
|
usageDesc = usage.bytes + " B";
|
|
} else if (usage && usage.bytes < 1000000) {
|
|
usageDesc = (usage.bytes / 1000.0).toFixed(1) + " KB";
|
|
} else if (usage && usage.bytes < 1000000000) {
|
|
usageDesc = (usage.bytes / 1000000.0).toFixed(1) + " MB";
|
|
} else if (usage) {
|
|
usageDesc = (usage.bytes / 1000000000.0).toFixed(1) + " GB";
|
|
}
|
|
|
|
let isPaused = false;
|
|
if (
|
|
usage &&
|
|
or(usage.status, "")
|
|
.toLowerCase()
|
|
.includes("pause")
|
|
) {
|
|
isPaused = true;
|
|
}
|
|
let isCellular = true;
|
|
let canHologram = user.hasFeature("billing");
|
|
// device.settings.platform === pond.DevicePlatform.DEVICE_PLATFORM_ELECTRON ||
|
|
// device.settings.platform === pond.DevicePlatform.DEVICE_PLATFORM_V2_CELLULAR;
|
|
return (
|
|
<Grid
|
|
container
|
|
direction="row"
|
|
alignItems="center"
|
|
spacing={1}
|
|
wrap={width === "xs" ? "nowrap" : "wrap"}
|
|
className={width === "xs" ? classes.chipContainer : undefined}>
|
|
{device.settings.platform > 0 && (
|
|
<Grid>
|
|
<Tooltip title={connectivity.tooltip}>
|
|
<Chip
|
|
variant={modemComponent ? "filled" : "outlined"}
|
|
clickable={modemComponent !== null}
|
|
onClick={() => {
|
|
// console.log(modemComponent)
|
|
// console.log(modemComponent?.key())
|
|
if (modemComponent && modemComponent.key()) {
|
|
navigate(pathToDevice() + "/components/" + modemComponent.key());
|
|
}
|
|
}}
|
|
label={connectivity.description}
|
|
icon={connectivity.icon}
|
|
onDelete={() => {
|
|
if (modemComponent && modemComponent.key()) {
|
|
navigate(pathToDevice() + "/components/" + modemComponent.key());
|
|
}
|
|
}}
|
|
deleteIcon={modemComponent ? <Launch /> : <React.Fragment />}
|
|
/>
|
|
</Tooltip>
|
|
</Grid>
|
|
)}
|
|
{notNull(device.status.power) && (
|
|
<Grid>
|
|
<Tooltip title={power.description}>
|
|
<Chip
|
|
variant={powerComponent ? "filled" : "outlined"}
|
|
clickable={powerComponent !== null}
|
|
onClick={() => {
|
|
if (powerComponent && powerComponent.key()) {
|
|
navigate(pathToDevice() + "/components/" + powerComponent.key());
|
|
}
|
|
}}
|
|
label={power.description}
|
|
icon={power.icon}
|
|
onDelete={() => {
|
|
if (powerComponent && powerComponent.key()) {
|
|
navigate(pathToDevice() + "/components/" + powerComponent.key());
|
|
}
|
|
}}
|
|
deleteIcon={powerComponent ? <Launch /> : <React.Fragment />}
|
|
/>
|
|
</Tooltip>
|
|
</Grid>
|
|
)}
|
|
|
|
{hasVersion && (
|
|
<Grid>
|
|
<VersionChip version={currentVersion} available={latestFirmware} />
|
|
</Grid>
|
|
)}
|
|
{isCellular && iccid && (
|
|
<Grid>
|
|
<Tooltip title={isPaused ? "Data paused" : "Data enabled"}>
|
|
<Chip
|
|
onClick={() => copySim(iccid)}
|
|
label={"SIM " + iccid.substring(iccid.length - 5)}
|
|
icon={<SimCard />}
|
|
/>
|
|
</Tooltip>
|
|
</Grid>
|
|
)}
|
|
{isCellular && usage && usage.bytes > 0 && (
|
|
<Grid>
|
|
<Tooltip title="Estimated usage in the past 24 hours">
|
|
<Chip
|
|
variant="outlined"
|
|
label={usageDesc}
|
|
icon={<DataUsage />}
|
|
clickable={canHologram}
|
|
onClick={() => {
|
|
// if (canHologram) setHologramDialog(true);
|
|
}}
|
|
/>
|
|
</Tooltip>
|
|
</Grid>
|
|
)}
|
|
{!device.status.synced && (
|
|
<Grid>
|
|
<StatusChip status="pending" />
|
|
</Grid>
|
|
)}
|
|
{user.allowedTo("provision") && <DeviceTags device={device} disableAdd={disableAddTag} />}
|
|
</Grid>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<React.Fragment>
|
|
{loading ? <Skeleton variant="text" width={width === "xs" ? 250 : 350} /> : chips()}
|
|
{/* <DeviceHologram device={device} open={hologramDialog} setOpen={setHologramDialog} /> */}
|
|
</React.Fragment>
|
|
);
|
|
}
|