feat: added notification rendering

This commit is contained in:
Sergey Yarkov 2022-02-21 23:57:43 +03:00
parent 4b846a7b27
commit 981a0ef642
5 changed files with 60 additions and 15 deletions

View File

@ -1,27 +1,35 @@
import React from 'react'; import React from 'react';
import { Menu, MenuButton, MenuList, MenuGroup, IconButton, MenuDivider } from '@chakra-ui/react'; import moment from 'moment';
import { Menu, MenuButton, MenuList, MenuItem, MenuGroup, IconButton, MenuDivider, Flex, Text } from '@chakra-ui/react';
import { Skeleton } from '@chakra-ui/skeleton'; import { Skeleton } from '@chakra-ui/skeleton';
import { MdNotifications } from 'react-icons/md'; import { MdNotifications, MdOutlineMessage } from 'react-icons/md';
import { useRootStore } from '@educt/hooks/useRootStore';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
export interface INotificationsProps { /**
count?: number | undefined; * Hooks
} */
import { useHistory } from 'react-router-dom';
import { useRootStore } from '@educt/hooks/useRootStore';
const Notifications: React.FC<INotificationsProps> = observer(props => { const Notifications: React.FC = observer(() => {
const { const {
userStore: { me }, userStore: { me },
} = useRootStore(); } = useRootStore();
const history = useHistory();
const { count, ...menuProps } = props;
if (me === null) { if (me === null) {
return <Skeleton width='50px' height='40px' mr={3} ml={3} borderRadius='md' />; return <Skeleton width='50px' height='40px' mr={3} ml={3} borderRadius='md' />;
} }
const count = me.notifications.length;
/**
* Filter types of notifications
*/
const messages = me.notifications.filter(notification => notification.type === 'MESSAGE');
return ( return (
<Menu isLazy {...menuProps}> <Menu>
<MenuButton <MenuButton
as={IconButton} as={IconButton}
mx='2' mx='2'
@ -41,9 +49,29 @@ const Notifications: React.FC<INotificationsProps> = observer(props => {
borderRadius: '100%', borderRadius: '100%',
}} }}
/> />
<MenuList> <MenuList minWidth='300px'>
<MenuGroup title={'Notifications'}> <MenuGroup title={count && count > 0 ? `${count} new notifications` : 'Notifications'}>
<MenuDivider /> <MenuDivider />
{/* MESSAGES */}
{messages.length !== 0 && (
<MenuItem onClick={() => history.push('/messages')} py='3' icon={<MdOutlineMessage />}>
<Flex flexDir='column' fontSize={'sm'}>
<Text as='span' mr='3'>
You have <b>{messages.length}</b> new private messages
</Text>
<Text as='span' fontSize={'xs'} color='gray.500' justifySelf='flex-start'>
{moment(messages[0].time).fromNow()}
</Text>
</Flex>
</MenuItem>
)}
{/* EMPTY NOTIFICATIONS */}
{me.notifications.length === 0 && (
<Text fontSize={'sm'} color='gray.500' textAlign='center' py='3' userSelect={'none'}>
You have no notifications
</Text>
)}
</MenuGroup> </MenuGroup>
</MenuList> </MenuList>
</Menu> </Menu>

View File

@ -2,7 +2,7 @@ import React from 'react';
import { Flex, Box, BoxProps } from '@chakra-ui/react'; import { Flex, Box, BoxProps } from '@chakra-ui/react';
import { Logo } from './Logo'; import { Logo } from './Logo';
import { Profile } from './Profile'; import { Profile } from './Profile';
import { INotificationsProps, Notifications } from './Notifications'; import { Notifications } from './Notifications';
import ColorModeSwitcher from '@educt/components/ColorModeSwitcher'; import ColorModeSwitcher from '@educt/components/ColorModeSwitcher';
import NavMobile from '@educt/components/Nav/Mobile'; import NavMobile from '@educt/components/Nav/Mobile';
import type { ColorModeSwitcherProps } from '../ColorModeSwitcher/ColorModeSwitcher'; import type { ColorModeSwitcherProps } from '../ColorModeSwitcher/ColorModeSwitcher';
@ -15,7 +15,7 @@ import { useColorModeValue, useMediaQuery } from '@chakra-ui/react';
interface IHeaderComposition { interface IHeaderComposition {
Logo: React.FC<BoxProps>; Logo: React.FC<BoxProps>;
ThemeSwitcher: React.FC<ColorModeSwitcherProps>; ThemeSwitcher: React.FC<ColorModeSwitcherProps>;
Notifications: React.FC<INotificationsProps>; Notifications: React.FC;
Profile: React.FC; Profile: React.FC;
} }

View File

@ -1,5 +1,12 @@
import type { RouteComponentProps } from 'react-router-dom'; import type { RouteComponentProps } from 'react-router-dom';
import { AttachmentFileType, ColorType, LessonProgress, LessonVideoType, LinkType } from '@educt/types'; import {
AttachmentFileType,
ColorType,
LessonProgress,
LessonVideoType,
LinkType,
NotificationType,
} from '@educt/types';
import { CourseStatusEnum, UserRoleEnum } from '../enums'; import { CourseStatusEnum, UserRoleEnum } from '../enums';
export interface IAppConfig { export interface IAppConfig {
@ -135,6 +142,7 @@ export interface IMe extends IUser {
*/ */
courses?: UserCourseType[]; courses?: UserCourseType[];
likes: Array<Pick<ICourse, 'id'>>; likes: Array<Pick<ICourse, 'id'>>;
notifications: Array<NotificationType>;
isAdmin: boolean; isAdmin: boolean;
isTeacher: boolean; isTeacher: boolean;
isStudent: boolean; isStudent: boolean;

View File

@ -72,6 +72,7 @@ export default class UserStore {
email, email,
roles, roles,
likes, likes,
notifications,
contacts, contacts,
courses, courses,
created_at, created_at,
@ -91,6 +92,7 @@ export default class UserStore {
about, about,
last_login, last_login,
likes, likes,
notifications,
contacts, contacts,
courses, courses,
isAdmin: helpers.userContainRoles(roles, [UserRoleEnum.ADMIN]), isAdmin: helpers.userContainRoles(roles, [UserRoleEnum.ADMIN]),

View File

@ -76,6 +76,13 @@ export type HistoryMessageType = {
time: string; time: string;
}; };
export type NotificationType = {
id: string;
content: string;
time: string;
type: 'SYSTEM' | 'MESSAGE';
};
export type UserSeesionType = { export type UserSeesionType = {
sessionId: string | undefined; sessionId: string | undefined;
userId: string | undefined; userId: string | undefined;