fix: dom nesting bugs

This commit is contained in:
anik-ghosh-au7 2022-05-12 12:27:25 +05:30
parent de44c40de5
commit 0433d64737

View File

@ -1,360 +1,362 @@
import React, { ReactNode } from "react"; import React, { Fragment, ReactNode } from 'react';
import { import {
IconButton, IconButton,
Box, Box,
CloseButton, CloseButton,
Flex, Flex,
Image, Image,
HStack, HStack,
VStack, VStack,
Icon, Icon,
useColorModeValue, useColorModeValue,
Link, Link,
Text, Text,
BoxProps, BoxProps,
FlexProps, FlexProps,
Menu, Menu,
MenuButton, MenuButton,
MenuItem, MenuItem,
MenuList, MenuList,
Accordion, Accordion,
AccordionButton, AccordionButton,
AccordionPanel, AccordionPanel,
AccordionItem, AccordionItem,
AccordionIcon, AccordionIcon,
useMediaQuery, useMediaQuery,
} from "@chakra-ui/react"; } from '@chakra-ui/react';
import { import {
FiHome, FiHome,
FiUser, FiUser,
FiGlobe, FiGlobe,
FiCode, FiCode,
FiSettings, FiSettings,
FiMenu, FiMenu,
FiUsers, FiUsers,
FiChevronDown, FiChevronDown,
FiShieldOff, FiShieldOff,
} from "react-icons/fi"; } from 'react-icons/fi';
import { BiCustomize } from "react-icons/bi"; import { BiCustomize } from 'react-icons/bi';
import { AiOutlineKey } from "react-icons/ai"; import { AiOutlineKey } from 'react-icons/ai';
import { SiOpenaccess, SiJsonwebtokens } from "react-icons/si"; import { SiOpenaccess, SiJsonwebtokens } from 'react-icons/si';
import { MdSecurity } from "react-icons/md"; import { MdSecurity } from 'react-icons/md';
import { RiDatabase2Line } from "react-icons/ri"; import { RiDatabase2Line } from 'react-icons/ri';
import { BsCheck2Circle } from "react-icons/bs"; import { BsCheck2Circle } from 'react-icons/bs';
import { HiOutlineMail, HiOutlineOfficeBuilding } from "react-icons/hi"; import { HiOutlineMail, HiOutlineOfficeBuilding } from 'react-icons/hi';
import { IconType } from "react-icons"; import { IconType } from 'react-icons';
import { ReactText } from "react"; import { ReactText } from 'react';
import { useMutation, useQuery } from "urql"; import { useMutation, useQuery } from 'urql';
import { NavLink, useNavigate, useLocation } from "react-router-dom"; import { NavLink, useNavigate, useLocation } from 'react-router-dom';
import { useAuthContext } from "../contexts/AuthContext"; import { useAuthContext } from '../contexts/AuthContext';
import { AdminLogout } from "../graphql/mutation"; import { AdminLogout } from '../graphql/mutation';
import { MetaQuery } from "../graphql/queries"; import { MetaQuery } from '../graphql/queries';
interface SubRoutes { interface SubRoutes {
name: string; name: string;
icon: IconType; icon: IconType;
route: string; route: string;
} }
interface LinkItemProps { interface LinkItemProps {
name: string; name: string;
icon: IconType; icon: IconType;
route: string; route: string;
subRoutes?: SubRoutes[]; subRoutes?: SubRoutes[];
} }
const LinkItems: Array<LinkItemProps> = [ const LinkItems: Array<LinkItemProps> = [
{ {
name: "Environment ", name: 'Environment ',
icon: FiSettings, icon: FiSettings,
route: "/", route: '/',
subRoutes: [ subRoutes: [
{ {
name: "OAuth Config", name: 'OAuth Config',
icon: AiOutlineKey, icon: AiOutlineKey,
route: "/oauth-setting", route: '/oauth-setting',
}, },
{ name: "Roles", icon: FiUser, route: "/roles" }, { name: 'Roles', icon: FiUser, route: '/roles' },
{ {
name: "JWT Secrets", name: 'JWT Secrets',
icon: SiJsonwebtokens, icon: SiJsonwebtokens,
route: "/jwt-config", route: '/jwt-config',
}, },
{ {
name: "Session Storage", name: 'Session Storage',
icon: RiDatabase2Line, icon: RiDatabase2Line,
route: "/session-storage", route: '/session-storage',
}, },
{ {
name: "Email Configurations", name: 'Email Configurations',
icon: HiOutlineMail, icon: HiOutlineMail,
route: "/email-config", route: '/email-config',
}, },
{ {
name: "Domain White Listing", name: 'Domain White Listing',
icon: BsCheck2Circle, icon: BsCheck2Circle,
route: "/whitelist-variables", route: '/whitelist-variables',
}, },
{ {
name: "Organization Info", name: 'Organization Info',
icon: HiOutlineOfficeBuilding, icon: HiOutlineOfficeBuilding,
route: "/organization-info", route: '/organization-info',
}, },
{ name: "Access Token", icon: SiOpenaccess, route: "/access-token" }, { name: 'Access Token', icon: SiOpenaccess, route: '/access-token' },
{ {
name: "UI Customization", name: 'UI Customization',
icon: BiCustomize, icon: BiCustomize,
route: "/ui-customization", route: '/ui-customization',
}, },
{ name: "Database", icon: RiDatabase2Line, route: "/db-cred" }, { name: 'Database', icon: RiDatabase2Line, route: '/db-cred' },
{ {
name: " Security", name: ' Security',
icon: MdSecurity, icon: MdSecurity,
route: "/admin-secret", route: '/admin-secret',
}, },
], ],
}, },
{ name: "Users", icon: FiUsers, route: "/users" }, { name: 'Users', icon: FiUsers, route: '/users' },
]; ];
interface SidebarProps extends BoxProps { interface SidebarProps extends BoxProps {
onClose: () => void; onClose: () => void;
} }
export const Sidebar = ({ onClose, ...rest }: SidebarProps) => { export const Sidebar = ({ onClose, ...rest }: SidebarProps) => {
const { pathname } = useLocation(); const { pathname } = useLocation();
const [{ fetching, data }] = useQuery({ query: MetaQuery }); const [{ fetching, data }] = useQuery({ query: MetaQuery });
const [isNotSmallerScreen] = useMediaQuery("(min-width:600px)"); const [isNotSmallerScreen] = useMediaQuery('(min-width:600px)');
return ( return (
<Box <Box
transition="3s ease" transition="3s ease"
bg={useColorModeValue("white", "gray.900")} bg={useColorModeValue('white', 'gray.900')}
borderRight="1px" borderRight="1px"
borderRightColor={useColorModeValue("gray.200", "gray.700")} borderRightColor={useColorModeValue('gray.200', 'gray.700')}
w={{ base: "full", md: 60 }} w={{ base: 'full', md: 60 }}
pos="fixed" pos="fixed"
h="full" h="full"
{...rest} {...rest}
> >
<Flex h="20" alignItems="center" mx="18" justifyContent="space-between"> <Flex h="20" alignItems="center" mx="18" justifyContent="space-between">
<NavLink to="/"> <NavLink to="/">
<Flex alignItems="center"> <Flex alignItems="center">
<Image <Image
src="https://authorizer.dev/images/logo.png" src="https://authorizer.dev/images/logo.png"
alt="logo" alt="logo"
height="36px" height="36px"
/> />
<Text fontSize="large" ml="2" letterSpacing="3"> <Text fontSize="large" ml="2" letterSpacing="3">
AUTHORIZER AUTHORIZER
</Text> </Text>
</Flex> </Flex>
</NavLink> </NavLink>
<CloseButton display={{ base: "flex", md: "none" }} onClick={onClose} /> <CloseButton display={{ base: 'flex', md: 'none' }} onClick={onClose} />
</Flex> </Flex>
<Accordion defaultIndex={[0]} allowMultiple> <Accordion defaultIndex={[0]} allowMultiple>
<AccordionItem textAlign="center" border="none" w="100%"> <AccordionItem textAlign="center" border="none" w="100%">
{LinkItems.map((link) => {LinkItems.map((link) =>
link?.subRoutes ? ( link?.subRoutes ? (
<NavLink key={link.name} to={link.route}> <div key={link.name}>
<AccordionButton> <AccordionButton>
<Text fontSize="md"> <Text as="div" fontSize="md">
<NavItem <NavItem
icon={link.icon} icon={link.icon}
color={pathname === link.route ? "blue.500" : ""} color={pathname === link.route ? 'blue.500' : ''}
style={{outline: "unset"}} style={{ outline: 'unset' }}
height={12} height={12}
ml={-1} ml={-1}
mb={isNotSmallerScreen ? -1 : -4} mb={isNotSmallerScreen ? -1 : -4}
w={isNotSmallerScreen ? "100%" : "310%"} w={isNotSmallerScreen ? '100%' : '310%'}
> >
{link.name} <Fragment>
<Box display={{ base: "none", md: "flex" }} ml={12}> {link.name}
<FiChevronDown /> <Box display={{ base: 'none', md: 'flex' }} ml={12}>
</Box> <FiChevronDown />
</NavItem> </Box>
</Text> </Fragment>
</AccordionButton> </NavItem>
<AccordionPanel> </Text>
{link.subRoutes?.map((sublink) => ( </AccordionButton>
<NavLink <AccordionPanel>
key={sublink.name} {link.subRoutes?.map((sublink) => (
to={sublink.route} <NavLink
onClick={onClose} key={sublink.name}
> to={sublink.route}
{" "} onClick={onClose}
<Text fontSize="xs" ml={2}> >
<NavItem {' '}
icon={sublink.icon} <Text as="div" fontSize="xs" ml={2}>
color={pathname === sublink.route ? "blue.500" : ""} <NavItem
height={8} icon={sublink.icon}
> color={pathname === sublink.route ? 'blue.500' : ''}
{sublink.name} height={8}
</NavItem>{" "} >
</Text> {sublink.name}
</NavLink> </NavItem>{' '}
))} </Text>
</AccordionPanel> </NavLink>
</NavLink> ))}
) : ( </AccordionPanel>
<NavLink key={link.name} to={link.route}> </div>
{" "} ) : (
<Text fontSize="md" w="100%" mt={-2}> <NavLink key={link.name} to={link.route}>
<NavItem {' '}
icon={link.icon} <Text as="div" fontSize="md" w="100%" mt={-2}>
color={pathname === link.route ? "blue.500" : ""} <NavItem
height={12} icon={link.icon}
onClick={onClose} color={pathname === link.route ? 'blue.500' : ''}
> height={12}
{link.name} onClick={onClose}
</NavItem>{" "} >
</Text> {link.name}
</NavLink> </NavItem>{' '}
) </Text>
)} </NavLink>
<Link )
href="/playground" )}
target="_blank" <Link
style={{ href="/playground"
textDecoration: "none", target="_blank"
}} style={{
_focus={{ _boxShadow: "none" }} textDecoration: 'none',
> }}
<NavItem icon={FiCode}>API Playground</NavItem> _focus={{ _boxShadow: 'none' }}
</Link> >
</AccordionItem> <NavItem icon={FiCode}>API Playground</NavItem>
</Accordion> </Link>
</AccordionItem>
</Accordion>
{data?.meta?.version && ( {data?.meta?.version && (
<Flex alignContent="center"> <Flex alignContent="center">
{" "} {' '}
<Text <Text
color="gray.400" color="gray.400"
fontSize="sm" fontSize="sm"
textAlign="center" textAlign="center"
position="absolute" position="absolute"
bottom="5" bottom="5"
left="7" left="7"
> >
Current Version: {data.meta.version} Current Version: {data.meta.version}
</Text> </Text>
</Flex> </Flex>
)} )}
</Box> </Box>
); );
}; };
interface NavItemProps extends FlexProps { interface NavItemProps extends FlexProps {
icon: IconType; icon: IconType;
children: ReactText; children: ReactText | JSX.Element | JSX.Element[];
} }
export const NavItem = ({ icon, children, ...rest }: NavItemProps) => { export const NavItem = ({ icon, children, ...rest }: NavItemProps) => {
return ( return (
<Flex <Flex
align="center" align="center"
p="3" p="3"
mx="3" mx="3"
borderRadius="md" borderRadius="md"
role="group" role="group"
cursor="pointer" cursor="pointer"
_hover={{ _hover={{
bg: "blue.500", bg: 'blue.500',
color: "white", color: 'white',
}} }}
{...rest} {...rest}
> >
{icon && ( {icon && (
<Icon <Icon
mr="4" mr="4"
fontSize="16" fontSize="16"
_groupHover={{ _groupHover={{
color: "white", color: 'white',
}} }}
as={icon} as={icon}
/> />
)} )}
{children} {children}
</Flex> </Flex>
); );
}; };
interface MobileProps extends FlexProps { interface MobileProps extends FlexProps {
onOpen: () => void; onOpen: () => void;
} }
export const MobileNav = ({ onOpen, ...rest }: MobileProps) => { export const MobileNav = ({ onOpen, ...rest }: MobileProps) => {
const [_, logout] = useMutation(AdminLogout); const [_, logout] = useMutation(AdminLogout);
const { setIsLoggedIn } = useAuthContext(); const { setIsLoggedIn } = useAuthContext();
const navigate = useNavigate(); const navigate = useNavigate();
const handleLogout = async () => { const handleLogout = async () => {
await logout(); await logout();
setIsLoggedIn(false); setIsLoggedIn(false);
navigate("/", { replace: true }); navigate('/', { replace: true });
}; };
return ( return (
<Flex <Flex
ml={{ base: 0, md: 60 }} ml={{ base: 0, md: 60 }}
px={{ base: 4, md: 4 }} px={{ base: 4, md: 4 }}
height="20" height="20"
position="fixed" position="fixed"
right="0" right="0"
left="0" left="0"
alignItems="center" alignItems="center"
bg={useColorModeValue("white", "gray.900")} bg={useColorModeValue('white', 'gray.900')}
borderBottomWidth="1px" borderBottomWidth="1px"
borderBottomColor={useColorModeValue("gray.200", "gray.700")} borderBottomColor={useColorModeValue('gray.200', 'gray.700')}
justifyContent={{ base: "space-between", md: "flex-end" }} justifyContent={{ base: 'space-between', md: 'flex-end' }}
zIndex={99} zIndex={99}
{...rest} {...rest}
> >
<IconButton <IconButton
display={{ base: "flex", md: "none" }} display={{ base: 'flex', md: 'none' }}
onClick={onOpen} onClick={onOpen}
variant="outline" variant="outline"
aria-label="open menu" aria-label="open menu"
icon={<FiMenu />} icon={<FiMenu />}
/> />
<Image <Image
src="https://authorizer.dev/images/logo.png" src="https://authorizer.dev/images/logo.png"
alt="logo" alt="logo"
height="36px" height="36px"
display={{ base: "flex", md: "none" }} display={{ base: 'flex', md: 'none' }}
/> />
<HStack spacing={{ base: "0", md: "6" }}> <HStack spacing={{ base: '0', md: '6' }}>
<Flex alignItems={"center"}> <Flex alignItems={'center'}>
<Menu> <Menu>
<MenuButton <MenuButton
py={2} py={2}
transition="all 0.3s" transition="all 0.3s"
_focus={{ boxShadow: "none" }} _focus={{ boxShadow: 'none' }}
> >
<HStack mr={5}> <HStack mr={5}>
<FiUser /> <FiUser />
<VStack <VStack
display={{ base: "none", md: "flex" }} display={{ base: 'none', md: 'flex' }}
alignItems="flex-start" alignItems="flex-start"
spacing="1px" spacing="1px"
ml="2" ml="2"
> >
<Text fontSize="sm">Admin</Text> <Text fontSize="sm">Admin</Text>
</VStack> </VStack>
<Box display={{ base: "none", md: "flex" }}> <Box display={{ base: 'none', md: 'flex' }}>
<FiChevronDown /> <FiChevronDown />
</Box> </Box>
</HStack> </HStack>
</MenuButton> </MenuButton>
<MenuList <MenuList
bg={useColorModeValue("white", "gray.900")} bg={useColorModeValue('white', 'gray.900')}
borderColor={useColorModeValue("gray.200", "gray.700")} borderColor={useColorModeValue('gray.200', 'gray.700')}
> >
<MenuItem onClick={handleLogout}>Sign out</MenuItem> <MenuItem onClick={handleLogout}>Sign out</MenuItem>
</MenuList> </MenuList>
</Menu> </Menu>
</Flex> </Flex>
</HStack> </HStack>
</Flex> </Flex>
); );
}; };