link-stack/apps/link/app/(main)/_components/Sidebar.tsx
2025-11-21 14:55:28 +01:00

463 lines
12 KiB
TypeScript

"use client";
import { FC, useEffect, useState } from "react";
import {
Box,
Grid,
Typography,
List,
ListItemButton,
ListItemIcon,
ListItemText,
ListItemSecondaryAction,
Drawer,
Collapse,
} from "@mui/material";
import {
FeaturedPlayList as FeaturedPlayListIcon,
Person as PersonIcon,
Insights as InsightsIcon,
Logout as LogoutIcon,
Cottage as CottageIcon,
Settings as SettingsIcon,
ExpandCircleDown as ExpandCircleDownIcon,
Dvr as DvrIcon,
Assessment as AssessmentIcon,
LibraryBooks as LibraryBooksIcon,
School as SchoolIcon,
} from "@mui/icons-material";
import { usePathname } from "next/navigation";
import Link from "next/link";
import Image from "next/image";
import LinkLogo from "@app/../public/link-logo-small.png";
import { useSession, signOut } from "next-auth/react";
import { fonts } from "@link-stack/ui";
const openWidth = 270;
const closedWidth = 70;
const MenuItem = ({
name,
href,
Icon,
iconSize,
inset = false,
selected = false,
open = true,
badge,
depth = 0,
target = "_self",
}: any) => {
const { roboto } = fonts;
return (
<Link href={href} target={target}>
<ListItemButton
sx={{
p: 0,
mb: 1,
bl: iconSize === 0 ? "1px solid white" : "inherit",
}}
selected={selected}
>
{iconSize > 0 ? (
<ListItemIcon
sx={{
color: `white`,
minWidth: 0,
mr: 2,
textAlign: "center",
margin: open ? "0 8 0 0" : "0 auto",
}}
>
<Box
sx={{
width: iconSize,
height: iconSize,
mr: 0.5,
mt: "-4px",
}}
>
<Icon />
</Box>
</ListItemIcon>
) : (
<Box
sx={{
width: 30,
height: "28px",
position: "relative",
ml: "8px",
mr: "2px",
}}
>
<Box
sx={{
width: "1px",
height: "56px",
backgroundColor: "white",
position: "absolute",
left: "3px",
top: "-10px",
}}
/>
<Box
sx={{
width: "42px",
height: "42px",
position: "absolute",
top: "-27px",
left: "3px",
border: "solid 1px #fff",
borderColor: "transparent transparent transparent #fff",
borderRadius: "60px",
rotate: "-50deg",
}}
/>
{depth > 0 && (
<Box
sx={{
width: depth * 22,
height: "1px",
backgroundColor: "white",
position: "absolute",
left: "26px",
top: "14px",
}}
/>
)}
</Box>
)}
{open && (
<ListItemText
inset={inset}
primary={
<Typography
variant="body1"
sx={{
fontSize: 16,
fontFamily: roboto.style.fontFamily,
fontWeight: "bold",
border: 0,
textAlign: "left",
color: "white",
ml: depth * 3,
}}
>
{name}
</Typography>
}
/>
)}
{open && badge && badge > 0 ? (
<ListItemSecondaryAction>
<Typography
color="textSecondary"
variant="body1"
className="badge"
sx={{
backgroundColor: "#FFB620",
color: "black !important",
borderRadius: 10,
px: 1,
fontSize: 12,
fontWeight: "bold",
}}
>
{badge}
</Typography>
</ListItemSecondaryAction>
) : null}
</ListItemButton>
</Link>
);
};
interface SidebarProps {
open: boolean;
setOpen: (open: boolean) => void;
}
export const Sidebar: FC<SidebarProps> = ({
open,
setOpen,
}) => {
const pathname = usePathname();
const { data: session } = useSession();
const { poppins } = fonts;
const username = session?.user?.name || "";
// @ts-ignore
const roles = session?.user?.roles || [];
return (
<Drawer
sx={{ width: open ? openWidth : closedWidth, flexShrink: 0 }}
variant="permanent"
anchor="left"
open={open}
PaperProps={{
sx: {
width: open ? openWidth : closedWidth,
border: 0,
overflow: "visible",
},
}}
>
<Box
sx={{
position: "absolute",
top: 24,
right: open ? -8 : -16,
color: "#1C75FD",
rotate: open ? "90deg" : "-90deg",
}}
onClick={() => {
setOpen!(!open);
}}
>
<ExpandCircleDownIcon
sx={{
width: 24,
height: 24,
background: "white",
borderRadius: 500,
}}
/>
</Box>
<Grid
container
direction="column"
justifyContent="space-between"
wrap="nowrap"
spacing={0}
sx={{ backgroundColor: "#25272A", height: "100%", p: 2 }}
>
<Grid item container>
<Grid item sx={{ width: open ? "40px" : "100%" }}>
<Box
sx={{
width: "40px",
height: "40px",
margin: open ? "0" : "0 auto",
}}
>
<Image
src={LinkLogo}
alt="Link logo"
width={40}
height={40}
style={{
objectFit: "cover",
filter: "grayscale(100) brightness(100)",
}}
/>
</Box>
.
</Grid>
{open && (
<Grid item>
<Typography
variant="h2"
sx={{
fontSize: 26,
color: "white",
fontWeight: 700,
mt: 1,
ml: 0.5,
fontFamily: poppins.style.fontFamily,
}}
>
CDR Link
</Typography>
</Grid>
)}
</Grid>
<Grid item>
<Box
sx={{
height: "0.5px",
width: "100%",
backgroundColor: "#666",
mb: 1,
}}
/>
</Grid>
<Grid item>
<Typography
variant="h6"
sx={{
fontSize: 12,
color: "#999",
fontWeight: "bold",
textAlign: open ? "left" : "center",
}}
>
Hello
</Typography>
</Grid>
<Grid item>
<Typography
variant="h2"
sx={{
fontSize: 22,
color: "white",
mb: 1.5,
fontWeight: "bold",
textAlign: open ? "left" : "center",
}}
>
{open
? username
: username
.split(" ")
.map((name) => name.substring(0, 1))
.join("")}
</Typography>
</Grid>
<Grid item>
<Box
sx={{
height: "0.5px",
width: "100%",
backgroundColor: "#666",
mb: 2,
}}
/>
</Grid>
<Grid
item
container
direction="column"
sx={{
mt: "6px",
overflow: "scroll",
scrollbarWidth: "none",
msOverflowStyle: "none",
"&::-webkit-scrollbar": { display: "none" },
}}
flexGrow={1}
>
<List
component="nav"
sx={{
a: {
textDecoration: "none",
".MuiListItemButton-root": {
p: 1,
borderRadius: 2,
"&:hover": {
background: "#555",
},
".MuiTypography-root": {
p: {
color: "#999 !important",
fontSize: 16,
},
},
},
".Mui-selected": {
background: "#444",
color: "#fff !important",
".MuiTypography-root": {
p: {
color: "#fff !important",
fontSize: 16,
},
},
},
},
}}
>
<MenuItem
name="Dashboard"
href="/"
Icon={InsightsIcon}
iconSize={20}
selected={pathname === "/"}
open={open}
/>
<MenuItem
name="Documentation"
href="/docs"
Icon={LibraryBooksIcon}
iconSize={20}
selected={pathname.endsWith("/docs")}
open={open}
/>
{roles.includes("admin") && (
<>
<MenuItem
name="Admin"
href="/admin/bridge"
Icon={SettingsIcon}
iconSize={20}
open={open}
selected={pathname.startsWith("/admin")}
/>
<Collapse
in={open && pathname.startsWith("/admin/")}
timeout="auto"
unmountOnExit
onClick={undefined}
>
<List component="div" disablePadding>
<MenuItem
name="WhatsApp"
href="/admin/bridge/whatsapp"
iconSize={0}
selected={pathname.endsWith("/admin/bridge/whatsapp")}
open={open}
/>
<MenuItem
name="Signal"
href="/admin/bridge/signal"
iconSize={0}
selected={pathname.endsWith("/admin/bridge/signal")}
open={open}
/>
<MenuItem
name="Facebook"
href="/admin/bridge/facebook"
iconSize={0}
selected={pathname.endsWith("/admin/bridge/facebook")}
open={open}
/>
<MenuItem
name="Voice"
href="/admin/bridge/voice"
iconSize={0}
selected={pathname.endsWith("/admin/bridge/voice")}
open={open}
/>
<MenuItem
name="Webhooks"
href="/admin/bridge/webhooks"
iconSize={0}
selected={pathname.endsWith("/admin/bridge/webhooks")}
open={open}
/>
<MenuItem
name="OpenSearch"
href="/admin/opensearch"
iconSize={0}
selected={pathname.endsWith("/admin/opensearch")}
open={open}
/>
</List>
</Collapse>
</>
)}
<MenuItem
name="Logout"
href="/logout"
Icon={LogoutIcon}
iconSize={20}
open={open}
/>
</List>
</Grid>
</Grid>
</Drawer>
);
};