Skip to content

Commit

Permalink
Merge pull request #7 from UniversityWeb/feature/user-profile
Browse files Browse the repository at this point in the history
Feature/user profile
  • Loading branch information
AnhAnNek authored Sep 29, 2024
2 parents 5809eec + 9b23bf9 commit cc7fed2
Show file tree
Hide file tree
Showing 21 changed files with 1,140 additions and 242 deletions.
9 changes: 9 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"query-string": "^9.1.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-icons": "^5.3.0",
"react-router-dom": "^6.22.3",
"react-scripts": "5.0.1",
"sass": "^1.75.0",
Expand Down
153 changes: 153 additions & 0 deletions src/components/Drawers/RightSidebarForStudent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import React from 'react';
import {
Box,
VStack,
Text,
Image,
Avatar,
Drawer,
DrawerBody,
DrawerFooter,
DrawerHeader,
DrawerOverlay,
DrawerContent,
Skeleton,
} from '@chakra-ui/react';
import PropTypes from 'prop-types';

import styles from './Drawer.module.scss';

import { useNavigate } from 'react-router-dom';
import {
MdOutlineAssignment,
MdOutlineShoppingBag,
MdNotificationsNone,
MdLogout
} from 'react-icons/md';
import { PiCertificate } from "react-icons/pi";
import { IoBookOutline } from "react-icons/io5";
import MenuBookOutlinedIcon from '@mui/icons-material/MenuBookOutlined';
import AssignmentOutlinedIcon from '@mui/icons-material/AssignmentOutlined';
import ShoppingBagOutlinedIcon from '@mui/icons-material/ShoppingBagOutlined';
import WorkspacePremiumOutlinedIcon from '@mui/icons-material/WorkspacePremiumOutlined';
import NotificationsNoneOutlinedIcon from '@mui/icons-material/NotificationsNoneOutlined';
import LogoutIcon from '@mui/icons-material/Logout';
import config from '~/config';
import { isLoggedIn, removeLoginResponse } from '~/utils/authUtils';
import SidebarItem from '~/components/Drawers/SidebarItem';

DrawerRightDefault.propTypes = {
isOpen: PropTypes.bool,
onClose: PropTypes.func,
user: PropTypes.object,
isUserLoading: PropTypes.bool,
};

DrawerRightDefault.defaultProps = {
user: {
username: 'john',
fullName: 'john',
email: '[email protected]',
phoneNumber: '+84972640891',
bio: 'A student.',
gender: 'MALE',
dob: '2024-08-05',
role: 'ADMIN',
createdAt: '2024-08-05T13:47:06.794Z',
avatarSrc: '',
},
};

function DrawerRightDefault(props) {
const user = props.user;
const navigate = useNavigate();

const handleLogout = () => {
removeLoginResponse();
navigate(config.routes.login);
};

return (
<Drawer
isOpen={props?.isOpen}
placement="right"
onClose={props.onClose}
size={'sm'}
>
<DrawerOverlay />
<DrawerContent backgroundColor={'var(--white)'}>
<DrawerHeader borderBottomWidth="1px">
<Box
display="flex"
alignItems="center"
gap="4%"
justifyContent="start"
onClick={() => navigate(config.routes.user_profile_edit)}
_hover={{
transform: 'scale(1.05)',
transition: 'transform 0.2s ease',
backgroundColor: '#f8f8f8',
cursor: 'pointer',
}}
>
<Avatar size="xl" name={user?.fullName} src={user?.urlImage} />
{!isLoggedIn() || props?.isUserLoading ? (
<Skeleton height="20px" width="100vh" />
) : (
<Text className={styles.drawer__heading}>{user?.fullName}</Text>
)}
</Box>
</DrawerHeader>

<DrawerBody padding={0}>
<VStack ps="10px">
<SidebarItem
icon={IoBookOutline}
text="Enrolled Courses"
handleClick={() => navigate(config.routes.course_management_for_student)}
/>

<SidebarItem
icon={MdOutlineAssignment}
text="My Assignments"
handleClick={() => navigate('')}
/>

<SidebarItem
icon={MdOutlineShoppingBag}
text="My Orders"
handleClick={() => navigate('')}
/>

<SidebarItem
icon={PiCertificate}
text="My Certificates"
handleClick={() => navigate('')}
/>

<SidebarItem
icon={MdNotificationsNone}
text="Notifications"
handleClick={() => navigate(config.routes.notifications_for_student)}
/>

<SidebarItem
icon={MdLogout}
text="Logout"
handleClick={handleLogout}
/>>
</VStack>
</DrawerBody>

<DrawerFooter padding={0}>
<VStack>
<Image width={'100%'} objectFit="cover" alt="" />
<Image width={'100%'} objectFit="cover" alt="" />
</VStack>
</DrawerFooter>
</DrawerContent>
</Drawer>
);
}

export default DrawerRightDefault;
28 changes: 28 additions & 0 deletions src/components/Drawers/SidebarItem.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import { Box } from '@chakra-ui/react';

const SidebarItem = ({ icon: Icon, text, isActive, handleClick, size = 22 }) => {
return (
<Box
w="100%"
onClick={handleClick}
className="drawer__item"
style={{ textDecoration: 'none', border: 'none', cursor: 'pointer' }}
display="flex"
alignItems="center"
justifyContent="flex-start"
padding="10px"
_hover={{
transform: 'scale(1.05)',
transition: 'transform 0.2s ease',
backgroundColor: isActive ? '#e2e2e2' : '#f8f8f8',
cursor: 'pointer',
}}
>
{Icon && <Icon style={{ fontSize: size }} />}
<p style={{ marginLeft: '10px' }}>{text}</p>
</Box>
);
};

export default SidebarItem;
7 changes: 5 additions & 2 deletions src/components/Navbars/HomeNavbar/HomeNavbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import DrawerRightDefault from '~/components/Drawers/DrawerRightDefault';
import AuthService from '~/services/authService';
import { isLoggedIn } from '~/utils/authUtils';
import useCustomToast from '~/hooks/useCustomToast';
import { useNavigate } from 'react-router-dom';
import config from '~/config';

function HomeNavbar(props) {
const navigate = useNavigate();
const { errorToast } = useCustomToast();
const { isOpen, onOpen, onClose } = useDisclosure();
const [user, setUser] = useState(null);
Expand Down Expand Up @@ -37,7 +40,7 @@ function HomeNavbar(props) {
<img className="navbar--logo" src={TransientAppLogo} alt="Logo" style={{ width: '100px', height: '100px' }} />
<div className="navbar--list">
<div className="navbar--list__gap20">
<Button id="course" light onClick={props.onSelectBtn}>
<Button id="course" light onClick={() => navigate(config.routes.course)}>
Course
</Button>
{isLoggedIn() ? (
Expand All @@ -48,7 +51,7 @@ function HomeNavbar(props) {
<DrawerRightDefault user={user} isUserLoading={isUserLoading} isOpen={isOpen} onClose={onClose}></DrawerRightDefault>
</>
) : (
<Button id="login" light onClick={props.onSelectBtn}>
<Button id="login" light onClick={() => navigate(config.routes.login)}>
Login
</Button>
)}
Expand Down
95 changes: 95 additions & 0 deletions src/components/Navbars/NavbarForStudent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import React, { useState, useEffect } from 'react';
import './Navbar.scss';
import TransientAppLogo from '~/assets/images/TransientAppLogo.svg';
import Button from '~/components/Buttons/Button';
import { useDisclosure, Avatar, Spacer } from '@chakra-ui/react';
import AuthService from '~/services/authService';
import { isLoggedIn } from '~/utils/authUtils';
import useCustomToast from '~/hooks/useCustomToast';
import { useNavigate } from 'react-router-dom';
import config from '~/config';
import RightSidebarForStudent from '~/components/Drawers/RightSidebarForStudent';

function HomeNavbar(props) {
const navigate = useNavigate();
const { errorToast } = useCustomToast();
const { isOpen, onOpen, onClose } = useDisclosure();
const [user, setUser] = useState(null);
const [isUserLoading, setIsUserLoading] = useState(true);

useEffect(() => {
const fetchUser = async () => {
setIsUserLoading(true);
AuthService.getCurUser()
.then((user) => {
setUser(user);
})
.catch((e) => {
errorToast(e?.message);
})
.finally(() => {
setIsUserLoading(false);
});
};

fetchUser();
}, []);

return (
<div className="navbar">
<img
className="navbar--logo"
src={TransientAppLogo}
alt="Logo"
style={{ width: '100px', height: '100px' }}
/>
<div className="navbar--list">
<div className="navbar--list__gap20">
<Button
id="courses"
light
onClick={() =>
navigate(config.routes.course_management_for_student)
}
>
Courses
</Button>
<Button id="assignment" light onClick={() => navigate('')}>
Assignments
</Button>

<Spacer />

{isLoggedIn() ? (
<>
<div className="navbar__group">
<Avatar
size="lg"
cursor="pointer"
name={user?.fullName}
onClick={onOpen}
src={user?.urlImage}
/>
</div>
<RightSidebarForStudent
user={user}
isUserLoading={isUserLoading}
isOpen={isOpen}
onClose={onClose}
></RightSidebarForStudent>
</>
) : (
<Button
id="login"
light
onClick={() => navigate(config.routes.login)}
>
Login
</Button>
)}
</div>
</div>
</div>
);
}
export default React.memo(HomeNavbar);
5 changes: 4 additions & 1 deletion src/config/routes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ const routes = {
login: '/login',
register: '/register',
forgot_password: '/forgot-password',
user_profile_edit: '/profile'
user_profile_edit: '/profile',
otp_validation: '/otp-validation',
course_management_for_student: '/course-management-for-student',
notifications_for_student: '/notifications-for-student'
};

export default routes;
Loading

0 comments on commit cc7fed2

Please sign in to comment.