authorizer/dashboard/src/components/Menu.tsx

234 lines
4.9 KiB
TypeScript
Raw Normal View History

2022-01-19 16:50:25 +00:00
import React, { ReactNode } from 'react';
import {
IconButton,
Box,
CloseButton,
Flex,
Image,
HStack,
VStack,
Icon,
useColorModeValue,
Link,
Text,
BoxProps,
FlexProps,
Menu,
MenuButton,
MenuItem,
MenuList,
} from '@chakra-ui/react';
import {
FiHome,
2022-01-25 07:36:52 +00:00
FiCode,
2022-01-19 16:50:25 +00:00
FiSettings,
FiMenu,
FiUser,
FiUsers,
FiChevronDown,
} from 'react-icons/fi';
import { IconType } from 'react-icons';
import { ReactText } from 'react';
2022-03-09 06:23:34 +00:00
import { useMutation, useQuery } from 'urql';
2022-01-19 16:50:25 +00:00
import { NavLink, useNavigate, useLocation } from 'react-router-dom';
import { useAuthContext } from '../contexts/AuthContext';
import { AdminLogout } from '../graphql/mutation';
2022-03-09 06:23:34 +00:00
import { MetaQuery } from '../graphql/queries';
2022-01-19 16:50:25 +00:00
interface LinkItemProps {
name: string;
icon: IconType;
route: string;
}
const LinkItems: Array<LinkItemProps> = [
2022-02-05 03:45:36 +00:00
// { name: 'Home', icon: FiHome, route: '/' },
{ name: 'Environment Variables', icon: FiSettings, route: '/' },
2022-01-19 16:50:25 +00:00
{ name: 'Users', icon: FiUsers, route: '/users' },
];
interface SidebarProps extends BoxProps {
onClose: () => void;
}
export const Sidebar = ({ onClose, ...rest }: SidebarProps) => {
const { pathname } = useLocation();
2022-03-09 06:23:34 +00:00
const [{ fetching, data }] = useQuery({ query: MetaQuery });
2022-01-19 16:50:25 +00:00
return (
<Box
transition="3s ease"
bg={useColorModeValue('white', 'gray.900')}
borderRight="1px"
borderRightColor={useColorModeValue('gray.200', 'gray.700')}
w={{ base: 'full', md: 60 }}
pos="fixed"
h="full"
{...rest}
>
<Flex h="20" alignItems="center" mx="8" justifyContent="space-between">
<NavLink to="/">
<Flex alignItems="center">
<Image
src="https://authorizer.dev/images/logo.png"
alt="logo"
height="36px"
/>
<Text fontSize="large" ml="2" letterSpacing="3">
AUTHORIZER
</Text>
</Flex>
</NavLink>
<CloseButton display={{ base: 'flex', md: 'none' }} onClick={onClose} />
</Flex>
{LinkItems.map((link) => (
<NavLink key={link.name} to={link.route}>
<NavItem
icon={link.icon}
color={pathname === link.route ? 'blue.500' : ''}
>
{link.name}
</NavItem>
</NavLink>
))}
2022-01-25 07:36:52 +00:00
<Link
href="/playground"
target="_blank"
style={{
textDecoration: 'none',
}}
_focus={{ _boxShadow: 'none' }}
>
<NavItem icon={FiCode}>API Playground</NavItem>
</Link>
2022-03-09 06:23:34 +00:00
{data?.meta?.version && (
<Text
color="gray.600"
fontSize="sm"
textAlign="center"
position="absolute"
bottom="5"
left="7"
>
Current Version: {data.meta.version}
</Text>
)}
2022-01-19 16:50:25 +00:00
</Box>
);
};
interface NavItemProps extends FlexProps {
icon: IconType;
children: ReactText;
}
export const NavItem = ({ icon, children, ...rest }: NavItemProps) => {
return (
2022-01-25 07:36:52 +00:00
<Flex
align="center"
p="3"
mx="3"
borderRadius="md"
role="group"
cursor="pointer"
_hover={{
bg: 'blue.500',
color: 'white',
}}
{...rest}
2022-01-19 16:50:25 +00:00
>
2022-01-25 07:36:52 +00:00
{icon && (
<Icon
mr="4"
fontSize="16"
_groupHover={{
color: 'white',
}}
as={icon}
/>
)}
{children}
</Flex>
2022-01-19 16:50:25 +00:00
);
};
interface MobileProps extends FlexProps {
onOpen: () => void;
}
export const MobileNav = ({ onOpen, ...rest }: MobileProps) => {
const [_, logout] = useMutation(AdminLogout);
const { setIsLoggedIn } = useAuthContext();
const navigate = useNavigate();
const handleLogout = async () => {
await logout();
setIsLoggedIn(false);
navigate('/', { replace: true });
};
return (
<Flex
ml={{ base: 0, md: 60 }}
px={{ base: 4, md: 4 }}
height="20"
position="fixed"
right="0"
left="0"
alignItems="center"
bg={useColorModeValue('white', 'gray.900')}
borderBottomWidth="1px"
borderBottomColor={useColorModeValue('gray.200', 'gray.700')}
justifyContent={{ base: 'space-between', md: 'flex-end' }}
zIndex={99}
2022-01-19 16:50:25 +00:00
{...rest}
>
<IconButton
display={{ base: 'flex', md: 'none' }}
onClick={onOpen}
variant="outline"
aria-label="open menu"
icon={<FiMenu />}
/>
<Image
src="https://authorizer.dev/images/logo.png"
alt="logo"
height="36px"
display={{ base: 'flex', md: 'none' }}
/>
<HStack spacing={{ base: '0', md: '6' }}>
<Flex alignItems={'center'}>
<Menu>
<MenuButton
py={2}
transition="all 0.3s"
_focus={{ boxShadow: 'none' }}
>
<HStack>
<FiUser />
<VStack
display={{ base: 'none', md: 'flex' }}
alignItems="flex-start"
spacing="1px"
ml="2"
>
<Text fontSize="sm">Admin</Text>
</VStack>
<Box display={{ base: 'none', md: 'flex' }}>
<FiChevronDown />
</Box>
</HStack>
</MenuButton>
<MenuList
bg={useColorModeValue('white', 'gray.900')}
borderColor={useColorModeValue('gray.200', 'gray.700')}
>
<MenuItem onClick={handleLogout}>Sign out</MenuItem>
</MenuList>
</Menu>
</Flex>
</HStack>
</Flex>
);
};