mirror of
https://github.com/sergeyyarkov/educt-client.git
synced 2026-10-11 02:09:08 +03:00
feat: added notification rendering
This commit is contained in:
parent
4b846a7b27
commit
981a0ef642
@ -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>
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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]),
|
||||||
|
|||||||
7
src/types/index.d.ts
vendored
7
src/types/index.d.ts
vendored
@ -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;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user