imported the gate and terminal related files to prep for the aviation map
This commit is contained in:
parent
e2e061151b
commit
505cb8e3aa
25 changed files with 4868 additions and 9 deletions
509
src/pages/Terminals.tsx
Normal file
509
src/pages/Terminals.tsx
Normal file
|
|
@ -0,0 +1,509 @@
|
|||
import {
|
||||
Tab,
|
||||
Tabs,
|
||||
Button,
|
||||
Theme,
|
||||
useTheme,
|
||||
Menu,
|
||||
MenuItem,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions
|
||||
} from "@mui/material";
|
||||
import { Terminal } from "models";
|
||||
import { useTerminalAPI, useGlobalState } from "providers";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import GateSettings from "gate/GateSettings";
|
||||
import PageContainer from "./PageContainer";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import TerminalSettings from "terminal/TerminalSettings";
|
||||
import { Delete, MoreVert, ExitToApp as RemoveSelfIcon } from "@mui/icons-material";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import { blue, green, red } from "@mui/material/colors";
|
||||
import ResponsiveDialog from "common/ResponsiveDialog";
|
||||
import { useSnackbar, useUserAPI } from "hooks";
|
||||
import { Gate } from "models/Gate";
|
||||
import GateList from "gate/GateList";
|
||||
import { Scope } from "models";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import ObjectUsers from "user/ObjectUsers";
|
||||
import ObjectTeams from "teams/ObjectTeams";
|
||||
import ObjectUsersIcon from "@mui/icons-material/AccountCircle";
|
||||
import ObjectTeamsIcon from "@mui/icons-material/SupervisedUserCircle";
|
||||
import ShareObject from "user/ShareObject";
|
||||
import RemoveSelfFromObject from "user/RemoveSelfFromObject";
|
||||
import AddGateFab from "gate/AddGateFab";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
|
||||
const parentTab = {
|
||||
"&": {
|
||||
margin: "0px",
|
||||
marginTop: "4px",
|
||||
marginLeft: "4px",
|
||||
animationDuration: "10s",
|
||||
background: "rgba(150, 150, 150, 0)",
|
||||
|
||||
borderRadius: "-5px",
|
||||
borderTopLeftRadius: "6px",
|
||||
borderTopRightRadius: "6px"
|
||||
},
|
||||
"&:hover": {
|
||||
background: "linear-gradient(rgba(150, 150, 150, 0.2), rgba(150, 150, 150, 0))"
|
||||
}
|
||||
};
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
tab: {
|
||||
...parentTab,
|
||||
minWidth: theme.spacing(25),
|
||||
left: 0,
|
||||
height: "100%",
|
||||
background: theme.palette.background.paper
|
||||
},
|
||||
smallTab: {
|
||||
...parentTab,
|
||||
width: theme.spacing(8),
|
||||
minWidth: theme.spacing(8),
|
||||
background: theme.palette.background.paper
|
||||
},
|
||||
selectedTab: {
|
||||
borderRadius: "-5px",
|
||||
borderTopLeftRadius: "6px",
|
||||
borderTopRightRadius: "6px",
|
||||
background: theme.palette.background.default,
|
||||
"&:hover": {
|
||||
background:
|
||||
"linear-gradient(rgba(150, 150, 150, 0.3)," + theme.palette.background.default + " 80%)"
|
||||
}
|
||||
},
|
||||
tabText: {
|
||||
position: "absolute",
|
||||
left: theme.spacing(2),
|
||||
color: "transparent",
|
||||
textAlign: "left",
|
||||
width: "80%",
|
||||
backgroundImage: "linear-gradient(to right, white 70%, rgba(200, 200, 200, 0) 87.5%)",
|
||||
backgroundClip: "text",
|
||||
WebkitBackgroundClip: "text",
|
||||
overflowX: "hidden",
|
||||
whiteSpace: "nowrap",
|
||||
top: 12
|
||||
},
|
||||
icon: {
|
||||
display: "flex",
|
||||
position: "absolute",
|
||||
right: 0,
|
||||
top: 6,
|
||||
padding: 6,
|
||||
marginRight: "2px",
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: "18px",
|
||||
background: "rgba(0,0,0,0)",
|
||||
"&:hover": {
|
||||
background:
|
||||
"radial-gradient(closest-side, rgba(150, 150, 150, 0.5) 50%, rgba(150, 150, 150, 0.5))"
|
||||
}
|
||||
},
|
||||
green: {
|
||||
marginRight: 0,
|
||||
paddingRight: 0,
|
||||
color: green["500"],
|
||||
"&:hover": {
|
||||
color: green["600"]
|
||||
}
|
||||
},
|
||||
red: {
|
||||
marginRight: 0,
|
||||
paddingRight: 0,
|
||||
color: red["500"],
|
||||
"&:hover": {
|
||||
color: red["600"]
|
||||
}
|
||||
},
|
||||
blueIcon: {
|
||||
color: blue["500"],
|
||||
"&:hover": {
|
||||
color: blue["600"]
|
||||
}
|
||||
},
|
||||
addGate: {
|
||||
position: "absolute",
|
||||
bottom: 20,
|
||||
right: 20,
|
||||
backgroundColor: theme.palette.primary.main
|
||||
}
|
||||
}));
|
||||
|
||||
interface Props {
|
||||
terminal?: Terminal;
|
||||
}
|
||||
|
||||
export default function Terminals(props: Props) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const terminalAPI = useTerminalAPI();
|
||||
const [value, setValue] = useState(0);
|
||||
const [terminals, setTerminals] = useState<Terminal[]>([]);
|
||||
const [gates, setGates] = useState<Gate[]>([]);
|
||||
// map using the terminal key and the gates for that terminal
|
||||
const [gateMap, setGateMap] = useState<Map<string, Gate[]>>(new Map<string, Gate[]>());
|
||||
const [displayGates, setDisplayGates] = useState<Gate[]>([]);
|
||||
const [gateDialog, setGateDialog] = useState(false);
|
||||
const classes = useStyles();
|
||||
const theme = useTheme();
|
||||
const [addTerminal, setAddTerminal] = useState(false);
|
||||
const [tabClick, setTabClick] = useState(true);
|
||||
const [menuAnchorEl, setMenuAnchorEl] = useState<Element | null>(null);
|
||||
const [currentTerminal, setCurrentTerminal] = useState<Terminal>();
|
||||
const [removeTerminal, setRemoveTerminal] = useState(false);
|
||||
const { openSnack } = useSnackbar();
|
||||
const [{ user, as }] = useGlobalState();
|
||||
const userAPI = useUserAPI();
|
||||
const [permissions, setPermissions] = useState<pond.Permission[]>([]);
|
||||
const [userSharing, setUserSharing] = useState(false);
|
||||
const [teamSharing, setTeamSharing] = useState(false);
|
||||
const [baseShareDialog, setBaseShareDialog] = useState(false);
|
||||
const [removeSelfDialog, setRemoveSelfDialog] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (currentTerminal) {
|
||||
let key = currentTerminal?.key;
|
||||
let kind = "terminal";
|
||||
if (as) {
|
||||
key = as;
|
||||
kind = "team";
|
||||
}
|
||||
userAPI.getUser(user.id(), { key: key, kind: kind } as Scope).then(resp => {
|
||||
setPermissions(resp.permissions);
|
||||
});
|
||||
}
|
||||
}, [as, userAPI, user, currentTerminal]);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.terminal) {
|
||||
setCurrentTerminal(props.terminal);
|
||||
setDisplayGates(gateMap.get(props.terminal.key) ?? []);
|
||||
}
|
||||
}, [props.terminal, gateMap]);
|
||||
|
||||
const load = useCallback(() => {
|
||||
console.log(loading)
|
||||
if (loading) return;
|
||||
console.log("terminal load")
|
||||
setLoading(true);
|
||||
terminalAPI
|
||||
.listTerminalsAndGates(200, 0)
|
||||
.then(resp => {
|
||||
console.log(resp)
|
||||
setTerminals(resp.data.terminals.map(a => Terminal.any(a)));
|
||||
let allGates = resp.data.gates.map(t => Gate.any(t));
|
||||
setGates(allGates);
|
||||
let tMap: Map<string, Gate[]> = new Map<string, Gate[]>();
|
||||
allGates.forEach(gate => {
|
||||
let mapEntry = tMap.get(gate.terminal());
|
||||
if (mapEntry) {
|
||||
mapEntry.push(gate);
|
||||
} else {
|
||||
tMap.set(gate.terminal(), [gate]);
|
||||
}
|
||||
setGateMap(tMap);
|
||||
setDisplayGates(allGates);
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
openSnack("There was a problem loading your terminals");
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}, [terminalAPI, openSnack]); //eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
useEffect(() => {
|
||||
console.log("load use")
|
||||
load();
|
||||
}, [load]);
|
||||
|
||||
const remove = () => {
|
||||
if (currentTerminal) {
|
||||
terminalAPI
|
||||
.removeTerminal(currentTerminal.key)
|
||||
.then(resp => {
|
||||
openSnack("Terminal Deleted");
|
||||
let a = terminals;
|
||||
a.splice(terminals.indexOf(currentTerminal), 1);
|
||||
setTerminals([...a]);
|
||||
})
|
||||
.catch(err => {
|
||||
openSnack("Failed to delete terminal");
|
||||
})
|
||||
.finally(() => {
|
||||
setRemoveTerminal(false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const terminalMenu = () => {
|
||||
if (currentTerminal === undefined) return;
|
||||
return (
|
||||
<Menu
|
||||
id="terminalMenu"
|
||||
anchorEl={menuAnchorEl ? menuAnchorEl : null}
|
||||
open={menuAnchorEl !== null}
|
||||
onClose={() => {
|
||||
setMenuAnchorEl(null);
|
||||
}}>
|
||||
{permissions.includes(pond.Permission.PERMISSION_WRITE) && (
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
setAddTerminal(true);
|
||||
setMenuAnchorEl(null);
|
||||
}}
|
||||
aria-label="Edit Terminal"
|
||||
dense>
|
||||
<ListItemIcon>
|
||||
<EditIcon className={classes.green} />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Edit Terminal" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{permissions.includes(pond.Permission.PERMISSION_WRITE) && (
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
setRemoveTerminal(true);
|
||||
setMenuAnchorEl(null);
|
||||
}}
|
||||
aria-label="Remove Terminal"
|
||||
dense>
|
||||
<ListItemIcon>
|
||||
<Delete className={classes.red} />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary="Delete Terminal" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{permissions.includes(pond.Permission.PERMISSION_USERS) && (
|
||||
<MenuItem
|
||||
dense
|
||||
onClick={() => {
|
||||
setUserSharing(true);
|
||||
setMenuAnchorEl(null);
|
||||
}}>
|
||||
<ListItemIcon>
|
||||
<ObjectUsersIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Users" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{permissions.includes(pond.Permission.PERMISSION_USERS) && (
|
||||
<MenuItem
|
||||
dense
|
||||
onClick={() => {
|
||||
setTeamSharing(true);
|
||||
setMenuAnchorEl(null);
|
||||
}}>
|
||||
<ListItemIcon>
|
||||
<ObjectTeamsIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Teams" />
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem
|
||||
dense
|
||||
onClick={() => {
|
||||
setRemoveSelfDialog(true);
|
||||
setMenuAnchorEl(null);
|
||||
}}>
|
||||
<ListItemIcon>
|
||||
<RemoveSelfIcon className={classes.red} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Leave" />
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
|
||||
const changeTabs = (newValue: number) => {
|
||||
if (tabClick && newValue <= terminals.length) {
|
||||
setValue(newValue);
|
||||
if (terminals[newValue - 1]) {
|
||||
setDisplayGates(gateMap.get(terminals[newValue - 1].key) ?? []);
|
||||
} else {
|
||||
setDisplayGates(gates);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const gateDisplay = () => {
|
||||
return (
|
||||
<GateList
|
||||
gates={displayGates}
|
||||
terminals={terminals}
|
||||
useMobile={props.terminal !== undefined}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
//could update the tabs in the same way as the bin yard tabs
|
||||
const terminalTabs = () => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Tabs
|
||||
variant="scrollable"
|
||||
scrollButtons="auto"
|
||||
value={value}
|
||||
onChange={(_, v) => changeTabs(v)}
|
||||
TabIndicatorProps={{ style: { background: "rgba(0,0,0,0)" } }}>
|
||||
<Tab
|
||||
key={"all"}
|
||||
label="All"
|
||||
disableTouchRipple
|
||||
classes={{ root: classes.smallTab, selected: classes.selectedTab }}
|
||||
style={{ marginLeft: theme.spacing(1) }}
|
||||
/>
|
||||
{terminals.map((a, index) => (
|
||||
<Tab
|
||||
classes={{ root: classes.tab, selected: classes.selectedTab }}
|
||||
disableTouchRipple
|
||||
key={a.key}
|
||||
label={
|
||||
<span>
|
||||
<div className={classes.tabText}>{a.name}</div>
|
||||
<MoreVert
|
||||
onMouseEnter={() => setTabClick(false)}
|
||||
onMouseLeave={() => setTabClick(true)}
|
||||
className={classes.icon}
|
||||
onClick={event => {
|
||||
let target = event.currentTarget;
|
||||
setMenuAnchorEl(target);
|
||||
setCurrentTerminal(terminals[index]);
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
|
||||
<Tab
|
||||
classes={{ root: classes.smallTab, selected: classes.selectedTab }}
|
||||
label={terminals.length === 0 ? "Add Terminal" : <AddIcon />}
|
||||
onClick={() => {
|
||||
setCurrentTerminal(undefined);
|
||||
setAddTerminal(true);
|
||||
}}
|
||||
disableTouchRipple={true}
|
||||
/>
|
||||
</Tabs>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const removeDialog = () => {
|
||||
return (
|
||||
<ResponsiveDialog
|
||||
open={removeTerminal}
|
||||
onClose={() => {
|
||||
setRemoveTerminal(false);
|
||||
}}>
|
||||
<DialogTitle>Delete Terminal</DialogTitle>
|
||||
<DialogContent>Are you sure you wish to delete this Terminal?</DialogContent>
|
||||
<DialogActions>
|
||||
<Button>Cancel</Button>
|
||||
<Button onClick={remove}>Confirm</Button>
|
||||
</DialogActions>
|
||||
</ResponsiveDialog>
|
||||
);
|
||||
};
|
||||
|
||||
const sharingDialogs = () => {
|
||||
if (!currentTerminal) return;
|
||||
return (
|
||||
<React.Fragment>
|
||||
<ShareObject
|
||||
scope={{ kind: "terminal", key: currentTerminal.key } as Scope}
|
||||
label={currentTerminal.name}
|
||||
permissions={permissions}
|
||||
isDialogOpen={baseShareDialog}
|
||||
closeDialogCallback={() => {
|
||||
setBaseShareDialog(false);
|
||||
}}
|
||||
/>
|
||||
<ObjectUsers
|
||||
scope={{ kind: "terminal", key: currentTerminal.key } as Scope}
|
||||
label={currentTerminal.name}
|
||||
permissions={permissions}
|
||||
isDialogOpen={userSharing}
|
||||
closeDialogCallback={() => setUserSharing(false)}
|
||||
refreshCallback={() => {}}
|
||||
/>
|
||||
<ObjectTeams
|
||||
scope={{ kind: "terminal", key: currentTerminal.key } as Scope}
|
||||
label={currentTerminal.name}
|
||||
permissions={permissions}
|
||||
isDialogOpen={teamSharing}
|
||||
closeDialogCallback={() => setTeamSharing(false)}
|
||||
refreshCallback={() => {
|
||||
return true;
|
||||
}}
|
||||
/>
|
||||
<RemoveSelfFromObject
|
||||
scope={{ kind: "terminal", key: currentTerminal.key } as Scope}
|
||||
label={currentTerminal.name}
|
||||
isDialogOpen={removeSelfDialog}
|
||||
closeDialogCallback={removed => {
|
||||
if (removed) {
|
||||
let a = terminals;
|
||||
a.splice(terminals.indexOf(currentTerminal), 1);
|
||||
setTerminals([...a]);
|
||||
}
|
||||
setRemoveSelfDialog(false);
|
||||
}}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
<GateSettings
|
||||
open={gateDialog}
|
||||
close={newGate => {
|
||||
if (newGate) {
|
||||
if (newGate.terminal() !== "") {
|
||||
let tMap = gateMap;
|
||||
tMap.get(newGate.terminal())?.push(newGate);
|
||||
}
|
||||
let t = gates;
|
||||
t.push(newGate);
|
||||
setGates([...t]);
|
||||
}
|
||||
setGateDialog(false);
|
||||
}}
|
||||
terminals={terminals}
|
||||
/>
|
||||
<TerminalSettings
|
||||
open={addTerminal}
|
||||
closeDialog={newTerminal => {
|
||||
if (newTerminal) {
|
||||
let a = terminals;
|
||||
a.push(newTerminal);
|
||||
setTerminals([...a]);
|
||||
}
|
||||
setAddTerminal(false);
|
||||
}}
|
||||
terminal={currentTerminal}
|
||||
/>
|
||||
{!props.terminal && terminalTabs()}
|
||||
{terminalMenu()}
|
||||
{removeDialog()}
|
||||
{sharingDialogs()}
|
||||
{gateDisplay()}
|
||||
<AddGateFab
|
||||
onClick={() => {
|
||||
setGateDialog(true);
|
||||
}}
|
||||
pulse={gates.length < 1}
|
||||
/>
|
||||
</PageContainer>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue