import { Gate as IGate } from "models/Gate"; //import { MatchParams } from "navigation/Routes"; //import { Redirect, useHistory, useRouteMatch } from "react-router"; import React, { useCallback, useEffect, useState } from "react"; import PageContainer from "./PageContainer"; import { useGlobalState, useGateAPI, useUserAPI } from "providers"; import { Box, ButtonBase, Card, CircularProgress, Drawer, Grid2 as Grid, IconButton, MenuItem, Tab, Tabs, Theme, Typography } from "@mui/material"; import { pond } from "protobuf-ts/pond"; import DeviceLinkDrawer from "common/DeviceLinkDrawer"; import { Component, Device, Scope } from "models"; import GateActions from "gate/GateActions"; import GateDevice from "gate/GateDevice"; import ObjectControls from "common/ObjectControls"; import { Link } from "@mui/icons-material"; import Chat from "chat/Chat"; import PlaneIcon from "products/AviationIcons/PlaneIcon"; import NotesIcon from "@mui/icons-material/Notes"; import { useMobile, useSnackbar, useThemeType } from "hooks"; import { clone } from "lodash"; import { useNavigate, useParams } from "react-router-dom"; import { makeStyles } from "@mui/styles"; interface TabPanelProps { children?: React.ReactNode; index: any; value: any; } function TabPanelMine(props: TabPanelProps) { const { children, value, index, ...other } = props; return ( ); } interface Props { gateKey?: string; useMobile?: boolean; } const useStyles = makeStyles((theme: Theme) => ({ //const themeType = theme.palette.type; inactiveButton: { color: useThemeType() === "light" ? theme.palette.common.black : theme.palette.common.white, backgroundColor: "transparent", width: theme.spacing(5), height: theme.spacing(5), border: "1px solid", borderColor: theme.palette.divider }, activeButton: { color: useThemeType() === "light" ? theme.palette.common.black : theme.palette.common.white, backgroundColor: theme.palette.primary.main, width: theme.spacing(5), height: theme.spacing(5), border: "1px solid", borderColor: theme.palette.divider }, drawerPaper: { height: "100%", width: "30%" } })); export default function Gate(props: Props) { //const match = useRouteMatch(); //const gateID = props.gateID ?? match.params.gateID; const { gateKey } = props const gateID = gateKey ?? useParams<{ gateKey: string }>()?.gateKey ?? ""; const classes = useStyles(); const gateAPI = useGateAPI(); const userAPI = useUserAPI(); const [gate, setGate] = useState(IGate.create()); const [devices, setDevices] = useState>( new Map() ); const [components, setComponents] = useState([]); const [openDeviceDrawer, setOpenDeviceDrawer] = useState(false); const [loadingGate, setLoadingGate] = useState(false); const [{ user, as }] = useGlobalState(); const [permissions, setPermissions] = useState([]); const [tabVal, setTabVal] = useState(0); //const history = useHistory(); const navigate = useNavigate(); const [displayTab, setDisplayTab] = useState(0); const [openNoteDrawer, setOpenNoteDrawer] = useState(false); const isMobile = useMobile(); const [devPrefs, setDevPrefs] = useState>(new Map()); const { openSnack } = useSnackbar(); const [invalid, setInvalid] = useState(false); const goToMap = () => { navigate("/aviationMap", { state: { long: gate.longitude(), lat:gate.latitude() }}) }; useEffect(() => { let key = gateID; let kind = "gate"; if (as) { key = as; kind = "team"; } userAPI.getUser(user.id(), { key: key, kind: kind } as Scope).then(resp => { setPermissions(resp.permissions); }); }, [as, gateID, userAPI, user]); const loadGate = useCallback(() => { let id = gateID; setTabVal(0); if (loadingGate || id === undefined || id === "") return; setLoadingGate(true); gateAPI .getGatePageData(id, as) .then(resp => { //console.log(resp.data); let p = new Map(); Object.keys(resp.data.preferences).forEach(k => { let prefKey = parseInt(k); p.set( prefKey, pond.GatePreferences.fromObject(resp.data.preferences[k]).gateDevice ?? pond.GateDeviceType.GATE_DEVICE_TYPE_UNKNOWN ); }); setDevPrefs(p); if (resp.data.gate) { setGate(IGate.any(resp.data.gate)); } if (resp.data.linkedDevices) { let devMap = new Map(); resp.data.linkedDevices.forEach(dev => { if (dev.device?.settings?.deviceId) { devMap.set(dev.device.settings.deviceId.toString(), dev); } }); setDevices(devMap); } if (resp.data.linkedComponents) { setComponents(resp.data.linkedComponents.map(c => Component.any(c))); } }) .catch(err => { setInvalid(true); }) .finally(() => { setLoadingGate(false); }); //eslint-disable-next-line react-hooks/exhaustive-deps }, [gateAPI, gateID, as]); useEffect(() => { loadGate(); }, [loadGate]); const updateGateDevicePrefs = (deviceID: number, newPref: pond.GateDeviceType) => { gateAPI .updatePrefs(gate.key, "device", deviceID.toString(), newPref, [gate.key], ["gate"], as) .then(resp => { openSnack("Updated gate device type"); // have to do the clone method to force the select box to update let newPrefMap = clone(devPrefs); newPrefMap.set(deviceID, newPref); setDevPrefs(newPrefMap); }) .catch(err => { openSnack("Failed to update device type"); }); }; const deviceDrawer = () => { return ( None , PCA Unit ]} devicePrefChanged={(device, pref) => { updateGateDevicePrefs(device.id(), pref); }} open={openDeviceDrawer} close={() => { setOpenDeviceDrawer(false); }} linkedDevices={devices} linkedComponents={components} updateLinkedDevices={(device, linked) => { let devMap = devices; let id = device.device?.settings?.deviceId; if (id) { if (linked) { gateAPI .updateLink(gateID, "gate", id.toString(), "device", [ "read", "write", "grant", "revoke" ], as) .then(resp => { if (id) { devMap.set(id.toString(), device); setTabVal(id); } setDevices(devMap); }) .catch(err => { console.log("error linking device"); }); } else { gateAPI.updateLink(gateID, "gate", id.toString(), "device", [], as).then(resp => { if (id) { devMap.delete(id.toString()); if (tabVal === id) { let firstEntry = Array.from(devMap.values())[0]; if (firstEntry) { setTabVal(firstEntry.device?.settings?.deviceId ?? -1); } else { setTabVal(0); } } } setDevices(devMap); }); } } }} updateLinkedComponents={(deviceID, component, linked) => { let c = components; if (linked) { gateAPI .updateLink(gateID, "gate", deviceID + ":" + component.key(), "component", [ "read", "write", "grant", "revoke" ],as) .then(resp => { c.push(component); setComponents([...c]); }); } else { gateAPI .updateLink(gateID, "gate", deviceID + ":" + component.key(), "component", [], as) .then(resp => { c.forEach((comp, i) => { if (component.key() === comp.key()) { c.splice(i, 1); setComponents([...c]); } }); }); } }} /> ); }; const gateDisplay = () => { return ( {loadingGate ? ( ) : ( { setTabVal(newVal); }} aria-label="device tabs"> {Array.from(devices.values()).map(dev => { let name = "Device Not Found"; let devKey = -1; if (dev.device && dev.device.settings) { name = dev.device.settings.name; devKey = dev.device.settings.deviceId; } return ; })} {/* panel to show if there are no devices */} { setOpenDeviceDrawer(true); }} style={{ height: 150, width: "100%", margin: -15 }}> Connect Device Click here to add a device to the gate. To add an additional device to a gate use the "Link Device" icon on the top right side of this page {/* panel to show if there was an issue in the tab */} Device Not Found {Array.from(devices.values()).map(dev => { let devKey = 0; if (dev.device && dev.device.settings) { devKey = dev.device.settings.deviceId; if (tabVal === 0) { setTabVal(devKey); } } return ( ); })} )} ); }; const noteDrawer = () => { return ( { setOpenNoteDrawer(false); }} anchor="right" classes={{ paper: classes.drawerPaper }}> Notes ); }; return ( { setDisplayTab(0); }} className={displayTab === 0 ? classes.activeButton : classes.inactiveButton} component="span"> } linkDeviceFunction={() => { setOpenDeviceDrawer(true); }} notesButton={ { if (props.useMobile || isMobile) { setDisplayTab(1); } else { setOpenNoteDrawer(true); } }} size="small" style={{ marginTop: "0.3625rem", marginBottom: "0.3625rem", marginRight: "0.5rem" }} className={displayTab === 1 ? classes.activeButton : classes.inactiveButton} component="span"> } mapFunction={() => { goToMap(); }} actions={} permissions={permissions} devices={Array.from(devices.values()).map(compDev => Device.any(compDev.device))} /> {gate.name} {gateDisplay()} {/* tab for notes on mobile and the map drawer */} {/* drawer is for displaying notes on desktop */} {noteDrawer()} {deviceDrawer()} ); }