committed by
GitHub
4 changed files with 139 additions and 0 deletions
@ -0,0 +1,48 @@ |
|||
import React from 'react'; |
|||
|
|||
import { Box, Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerOverlay, Flex, IconButton, Image, useDisclosure } from '@chakra-ui/react'; |
|||
import { FiMenu } from 'react-icons/fi'; |
|||
|
|||
import Logo from "../assets/images/fastapi-logo.png"; |
|||
import SidebarItems from './SidebarItems'; |
|||
import UserInfo from './UserInfo'; |
|||
|
|||
|
|||
const Sidebar: React.FC = () => { |
|||
const { isOpen, onOpen, onClose } = useDisclosure(); |
|||
|
|||
return ( |
|||
<> |
|||
{/* Mobile */} |
|||
<IconButton onClick={onOpen} display={{ base: 'flex', md: 'none' }} aria-label="Open Menu" position="absolute" fontSize='20px' m={4} icon={<FiMenu />} /> |
|||
<Drawer isOpen={isOpen} placement="left" onClose={onClose}> |
|||
<DrawerOverlay /> |
|||
<DrawerContent bg="gray.100" maxW="250px"> |
|||
<DrawerCloseButton /> |
|||
<DrawerBody py={8}> |
|||
<Flex flexDir="column" justify="space-between" h="100%"> |
|||
<Box> |
|||
<Image src={Logo} alt="Logo" /> |
|||
<SidebarItems /> |
|||
</Box> |
|||
<UserInfo /> |
|||
</Flex> |
|||
</DrawerBody> |
|||
</DrawerContent> |
|||
</Drawer> |
|||
|
|||
{/* Desktop */} |
|||
<Box bg="white" p={3} h="100vh" position="sticky" top="0" display={{ base: 'none', md: 'flex' }}> |
|||
<Flex flexDir="column" justify="space-between" bg="gray.100" p={6} borderRadius={12}> |
|||
<Box> |
|||
<Image src={Logo} alt="Logo" w="180px" maxW="2xs" /> |
|||
<SidebarItems /> |
|||
</Box> |
|||
<UserInfo /> |
|||
</Flex> |
|||
</Box> |
|||
</> |
|||
); |
|||
} |
|||
|
|||
export default Sidebar; |
@ -0,0 +1,37 @@ |
|||
import React from 'react'; |
|||
|
|||
import { Flex, Icon, Text } from '@chakra-ui/react'; |
|||
import { FiBriefcase, FiHome, FiLogOut, FiUser, FiUsers } from 'react-icons/fi'; |
|||
import { Link } from 'react-router-dom'; |
|||
|
|||
const items = [ |
|||
{ icon: FiHome, title: 'Dashboard', path: "/" }, |
|||
{ icon: FiUser, title: 'Profile', path: "/profile" }, |
|||
{ icon: FiBriefcase, title: 'Items', path: "/items" }, |
|||
{ icon: FiUsers, title: 'Admin', path: "/admin" }, |
|||
{ icon: FiLogOut, title: 'Log out' } |
|||
]; |
|||
|
|||
const SidebarItems: React.FC = () => { |
|||
const listItems = items.map((item) => ( |
|||
<Flex w="100%" p={2} key={item.title} _hover={{ |
|||
background: "gray.200", |
|||
borderRadius: "12px", |
|||
}}> |
|||
<Link to={item.path || "/"}> |
|||
<Flex color="teal.500" gap={4}> |
|||
<Icon as={item.icon} alignSelf="center" /> |
|||
<Text>{item.title}</Text> |
|||
</Flex> |
|||
</Link> |
|||
</Flex> |
|||
)); |
|||
|
|||
return ( |
|||
<> |
|||
{listItems} |
|||
</> |
|||
); |
|||
}; |
|||
|
|||
export default SidebarItems; |
@ -0,0 +1,40 @@ |
|||
import React, { useEffect, useState } from 'react'; |
|||
|
|||
import { Avatar, Flex, Skeleton, Text } from '@chakra-ui/react'; |
|||
import { FaUserAstronaut } from 'react-icons/fa'; |
|||
|
|||
import { UserOut, UsersService } from '../client'; |
|||
|
|||
const UserInfo: React.FC = () => { |
|||
const [userData, setUserData] = useState<UserOut>(); |
|||
|
|||
useEffect(() => { |
|||
const fetchUserData = async () => { |
|||
try { |
|||
const userResponse = await UsersService.readUserMe(); |
|||
setUserData(userResponse); |
|||
} catch (error) { |
|||
// TODO: Handle error to give feedback to the user
|
|||
console.error(error); |
|||
} |
|||
}; |
|||
fetchUserData(); |
|||
}, []); |
|||
|
|||
return ( |
|||
<> |
|||
{userData ? ( |
|||
<Flex gap={2} maxW="180px"> |
|||
<Avatar icon={<FaUserAstronaut fontSize="18px" />} size='sm' alignSelf="center" /> |
|||
{/* TODO: Conditional tooltip based on email length */} |
|||
<Text color='gray' alignSelf={"center"} noOfLines={1} fontSize="14px">{userData.email}</Text> |
|||
</Flex> |
|||
) : |
|||
<Skeleton height='20px' /> |
|||
} |
|||
</> |
|||
); |
|||
|
|||
} |
|||
|
|||
export default UserInfo; |
@ -0,0 +1,14 @@ |
|||
import Sidebar from '../components/Sidebar'; |
|||
|
|||
import { Flex } from '@chakra-ui/react'; |
|||
|
|||
const Layout = ({ children }: { children: React.ReactNode }) => { |
|||
return ( |
|||
<Flex maxW="large" h="auto" position="relative"> |
|||
<Sidebar /> |
|||
{children} |
|||
</Flex> |
|||
); |
|||
}; |
|||
|
|||
export default Layout; |
Loading…
Reference in new issue