import { Button, CircularProgress, DialogActions, DialogContent, DialogTitle, Divider, Grid2 as Grid, IconButton, List, ListItem, TextField, Tooltip, Typography } from "@mui/material"; import { FileCopy } from "@mui/icons-material"; import ResponsiveDialog from "common/ResponsiveDialog"; import SearchSelect, { Option } from "common/SearchSelect"; import SelectDevicePlatform from "device/SelectDevicePlatform"; import { useBackpackAPI, useDeviceAPI, usePrevious, useSnackbar } from "hooks"; import { cloneDeep } from "lodash"; import { Backpack, Device } from "models"; import { backpackOptions, genericBackpacks } from "pbHelpers/Backpack"; import { pond } from "protobuf-ts/pond"; import React, { useEffect, useState } from "react"; import { useGlobalState } from "providers"; interface Props { isOpen: boolean; refreshCallback: Function; closeDialogCallback: Function; } export default function ProvisionDevice(props: Props) { const deviceAPI = useDeviceAPI(); const backpackAPI = useBackpackAPI(); const { error, success, warning, info } = useSnackbar(); const [{as}] = useGlobalState(); const { isOpen, closeDialogCallback, refreshCallback } = props; const [provisioned, setProvisioned] = useState(false); const [idHex, setIdHex] = useState(""); const [keyHex, setKeyHex] = useState(""); const [backpack, setBackpack] = useState(undefined); const [name, setName] = useState(""); const [description, setDescription] = useState(""); const [loading, setLoading] = useState(false); const [backpacks, setBackpacks] = useState([]); const [command, setCommand] = useState(""); const [deviceLoading, setDeviceLoading] = useState(false); const [platform, setPlatform] = useState( pond.DevicePlatform.DEVICE_PLATFORM_PHOTON ); const [device, setDevice] = useState(undefined); const prevIsOpen = usePrevious(isOpen); const deviceID: number = parseInt(idHex, 16); const setDefaultState = () => { setProvisioned(false); setIdHex(""); setKeyHex(""); setBackpack(undefined); setName(""); setDescription(""); setLoading(false); setBackpacks([]); setCommand(""); setDeviceLoading(false); setDevice(undefined); }; useEffect(() => { if (isOpen && !prevIsOpen) { setLoading(true); backpackAPI .listBackpacks() .then((response: any) => { const rawBackpacks = response.data.backpacks; let updatedBackpacks: Backpack[] = genericBackpacks(); if (rawBackpacks && rawBackpacks.length > 0) { rawBackpacks.forEach((backpack: any) => { updatedBackpacks.push(Backpack.any(backpack)); }); } setLoading(false); setBackpacks(updatedBackpacks.sort((a, b) => (a.name() > b.name() ? 1 : -1))); setBackpack(undefined); }) .catch((err: any) => { setDefaultState(); error(err ? err : "Error occured while loading device profiles"); }) .finally(() => setLoading(false)); } }, [backpackAPI, isOpen, prevIsOpen, error]); useEffect(() => { if (isOpen && provisioned && !device && !deviceLoading) { setDeviceLoading(true); const deviceID = parseInt(idHex, 16); deviceAPI .get(deviceID, undefined, undefined, undefined, as) .then(response => { let rDevice = Device.any(response.data); setDevice(rDevice); setName(rDevice.name()); setDescription(rDevice.settings.description); }) .catch(error => { console.error(error); setDevice( Device.create( pond.Device.create({ settings: pond.DeviceSettings.create({ deviceId: deviceID }) }) ) ); }) .finally(() => setDeviceLoading(false)); } }, [device, deviceAPI, deviceLoading, idHex, isOpen, provisioned]); const close = () => { if (provisioned) { refreshCallback(); } closeDialogCallback(); setDefaultState(); }; const generateCommand = (idHex: any, keyHex: any): string => { if (!idHex || !keyHex) { return ""; } return "set creds " + idHex + ":" + keyHex; }; const assembleBackpack = (): pond.BackpackSettings => { let assembledBackpack = backpack ? cloneDeep(backpack) : Backpack.create(); let agnosticDevice = assembledBackpack.settings.device ? cloneDeep(assembledBackpack.settings.device) : ({} as pond.DeviceSettings); agnosticDevice.deviceId = 0; agnosticDevice.platform = platform; agnosticDevice.product = assembledBackpack.settings.product; assembledBackpack.settings.device = agnosticDevice; return assembledBackpack.settings; }; const submitProvision = () => { setProvisioned(false); deviceAPI .add("", "", assembleBackpack(), as) .then((response: any) => { let updatedIdHex = response.data.idHex; let updatedKeyHex = response.data.keyHex; setIdHex(updatedIdHex); setKeyHex(updatedKeyHex); success("Successfully provisioned a new device (id: " + parseInt(updatedIdHex, 16) + ")"); setProvisioned(true); setCommand(generateCommand(updatedIdHex, updatedKeyHex)); }) .catch((error: any) => { error.response.data.error ? warning(error.response.data.error) : error("Error occured while provisioning a new device."); close(); }); }; const submitDeviceUpdate = () => { const deviceID = parseInt(idHex, 16); let settings = pond.DeviceSettings.create(device ? device.settings : { deviceId: deviceID }); settings.name = name; settings.description = description; deviceAPI .update(deviceID, settings, as) .then(() => { success("Device " + deviceID.toString() + " was successfully updated"); }) .catch((error: any) => { error.response.data.error ? warning(error.response.data.error) : error("Error occured while updating device " + deviceID.toString() + "."); close(); }) .finally(() => { setDevice(undefined); }); }; const copyID = () => { navigator.clipboard.writeText(idHex); info("ID copied to clipboard"); }; const copyKey = () => { navigator.clipboard.writeText(keyHex); info("Key copied to clipboard"); }; const copyCommand = () => { navigator.clipboard.writeText(command + "\n"); info("Command copied to clipboard"); }; const changeBackpack = (option: Option | null) => { let selectedBackpack = undefined; if (option) { const value = Number(option.value); selectedBackpack = backpacks.find(backpack => { let idMatch: boolean = backpack.id() === value; return idMatch && (value === 0 ? backpack.name() === option.label : true); }); } setBackpack(selectedBackpack); }; const content = () => { if (provisioned) { return ( {/* {window.NDEFReader && ( )} */} {deviceLoading ? ( ) : ( Update device name/description setName(event.target.value)} /> setDescription(event.target.value)} /> )} ); } const selectedBackpack = backpack ? ({ label: backpack.name(), value: backpack.id() } as Option) : undefined; return ( setPlatform(platform)} /> ); }; const actions = () => { return ( {!provisioned ? ( ) : ( )} ); }; return ( Provision Device {provisioned && ( Device ID: {deviceID} )} {content()} {actions()} ); }