feat: course status badge

This commit is contained in:
Sergey Yarkov 2021-10-12 23:38:03 +03:00
parent 962e43c81c
commit 02b2a4ee43
9 changed files with 96 additions and 39 deletions

2
.gitignore vendored
View File

@ -1,5 +1,7 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
.env
# dependencies # dependencies
/node_modules /node_modules
/.pnp /.pnp

View File

@ -0,0 +1,30 @@
import { Badge } from '@chakra-ui/layout';
import { CourseStatusEnum } from 'enums';
import React from 'react';
type CourseStatusBadgeProps = {
status: CourseStatusEnum;
};
const CourseStatusBadge: React.FC<CourseStatusBadgeProps> = ({ status }) => {
return (
<>
{(() => {
switch (status) {
case CourseStatusEnum.PUBLISHED:
return (
<Badge variant='subtle' colorScheme='green'>
Published
</Badge>
);
case CourseStatusEnum.DRAFT:
return <Badge variant='subtle'>Draft</Badge>;
default:
return null;
}
})()}
</>
);
};
export default CourseStatusBadge;

View File

@ -0,0 +1,3 @@
import CourseStatusBadge from './CourseStatusBadge';
export default CourseStatusBadge;

View File

@ -4,6 +4,11 @@ import { CoursesPageContext } from 'contexts';
import CategoryItem from './CategoryItem'; import CategoryItem from './CategoryItem';
import { ICategory } from 'interfaces'; import { ICategory } from 'interfaces';
import CategoryListLoading from './CategoryListLoading'; import CategoryListLoading from './CategoryListLoading';
/**
* Hooks
*/
import { useErrorHandler } from 'react-error-boundary';
import { useRootStore } from 'hooks/useRootStore'; import { useRootStore } from 'hooks/useRootStore';
type CategoryListPropsType = { type CategoryListPropsType = {
@ -12,16 +17,13 @@ type CategoryListPropsType = {
}; };
const CategoryList: React.FC<CategoryListPropsType> = ({ categories, isLoading }) => { const CategoryList: React.FC<CategoryListPropsType> = ({ categories, isLoading }) => {
const { courseStore } = useRootStore(); const { categoryStore } = useRootStore();
const { selectedCategory, setSelectedCategory } = useContext(CoursesPageContext); const { selectedCategory, setSelectedCategory } = useContext(CoursesPageContext);
const handleError = useErrorHandler();
/**
* Handle on changing category
*/
useEffect(() => { useEffect(() => {
console.log(`[LOG:] Selected category: ${selectedCategory?.title}`); categoryStore.loadCategories().catch(error => handleError(error));
courseStore.loadCourses({ category_id: selectedCategory?.id }); }, [categoryStore, handleError]);
}, [courseStore, selectedCategory]);
if (isLoading || categories === null) { if (isLoading || categories === null) {
return <CategoryListLoading />; return <CategoryListLoading />;

View File

@ -28,6 +28,7 @@ import { ICourse } from 'interfaces';
*/ */
import { useColorMode } from '@chakra-ui/color-mode'; import { useColorMode } from '@chakra-ui/color-mode';
import { useRootStore } from 'hooks/useRootStore'; import { useRootStore } from 'hooks/useRootStore';
import CourseStatusBadge from 'components/CourseStatusBadge';
type CourseItemPropsType = { type CourseItemPropsType = {
course: Omit<ICourse, 'teacher' | 'students' | 'lessons'>; course: Omit<ICourse, 'teacher' | 'students' | 'lessons'>;
@ -97,7 +98,10 @@ const CourseItem: React.FC<CourseItemPropsType> = ({ course }) => {
/> />
</Box> </Box>
<Box p='0 10px' mt='10px' pb='20px'> <Box p='0 10px' mt='10px' pb='20px'>
<Flex justifyContent='space-between'>
<Badge colorScheme='blue'>{course.category.title}</Badge> <Badge colorScheme='blue'>{course.category.title}</Badge>
{(me.isAdmin || me.isTeacher) && <CourseStatusBadge status={course.status} />}
</Flex>
<Heading as='h2' fontSize='xl' mt='5px'> <Heading as='h2' fontSize='xl' mt='5px'>
{course.title} {course.title}
</Heading> </Heading>

View File

@ -1,5 +1,5 @@
import React from 'react'; import React, { useContext, useEffect } from 'react';
import { Grid } from '@chakra-ui/react'; import { Box, Grid, Text } from '@chakra-ui/react';
/** /**
* Types * Types
@ -12,17 +12,36 @@ import { ICourse } from 'interfaces';
import CourseItem from './CourseItem'; import CourseItem from './CourseItem';
import CourseListLoading from './CourseListLoading'; import CourseListLoading from './CourseListLoading';
/**
* Hooks
*/
import { useRootStore } from 'hooks/useRootStore';
/**
* Contexts
*/
import { CoursesPageContext } from 'contexts';
type CourseListPropsType = { type CourseListPropsType = {
courses: Omit<ICourse, 'teacher' | 'students' | 'lessons'>[] | null; courses: Omit<ICourse, 'teacher' | 'students' | 'lessons'>[] | null;
isLoading: boolean; isLoading: boolean;
}; };
const CourseList: React.FC<CourseListPropsType> = ({ courses, isLoading }) => { const CourseList: React.FC<CourseListPropsType> = ({ courses, isLoading }) => {
const { courseStore } = useRootStore();
const { selectedCategory } = useContext(CoursesPageContext);
useEffect(() => {
courseStore.loadCourses({ category_id: selectedCategory?.id });
}, [courseStore, selectedCategory]);
if (isLoading || courses === null) { if (isLoading || courses === null) {
return <CourseListLoading />; return <CourseListLoading />;
} }
return ( return (
<>
{courses.length !== 0 ? (
<Grid <Grid
templateColumns='repeat(3, 1fr)' templateColumns='repeat(3, 1fr)'
gap='6' gap='6'
@ -35,10 +54,16 @@ const CourseList: React.FC<CourseListPropsType> = ({ courses, isLoading }) => {
}, },
}} }}
> >
{courses.map(course => { {courses.map(course => (
return <CourseItem key={course.id} course={course} />; <CourseItem key={course.id} course={course} />
})} ))}
</Grid> </Grid>
) : (
<Box textAlign='center' mt='10' userSelect='none'>
<Text color='gray.500'>There are no courses in this category.</Text>
</Box>
)}
</>
); );
}; };

View File

@ -1,4 +1,4 @@
import React, { useEffect } from 'react'; import React from 'react';
import { observer } from 'mobx-react-lite'; import { observer } from 'mobx-react-lite';
import { Flex, Tabs, TabList, Tab, Box, Heading, Text, Button } from '@chakra-ui/react'; import { Flex, Tabs, TabList, Tab, Box, Heading, Text, Button } from '@chakra-ui/react';
@ -10,14 +10,13 @@ import { AddIcon } from '@chakra-ui/icons';
*/ */
import CourseList from './components/CourseList'; import CourseList from './components/CourseList';
import CategoryList from './components/CategoryList'; import CategoryList from './components/CategoryList';
import LoadingPage from 'components/LoadingPage';
/** /**
* Hooks * Hooks
*/ */
import { useRootStore } from 'hooks/useRootStore'; import { useRootStore } from 'hooks/useRootStore';
import { CoursesPageContextProvider } from 'providers'; import { CoursesPageContextProvider } from 'providers';
import { useErrorHandler } from 'react-error-boundary';
import LoadingPage from 'components/LoadingPage';
/** /**
* Courses page * Courses page
@ -28,14 +27,6 @@ const CoursesPage: React.FC<IPageProps> = ({ title }) => {
categoryStore, categoryStore,
courseStore, courseStore,
} = useRootStore(); } = useRootStore();
const handleError = useErrorHandler();
useEffect(() => {
if (me !== null) {
categoryStore.loadCategories().catch(error => handleError(error));
// courseStore.loadCourses().catch(error => handleError(error));
}
}, [me, categoryStore, handleError]);
if (me === null) return <LoadingPage />; if (me === null) return <LoadingPage />;

View File

@ -53,7 +53,7 @@ const UpdateUserContactsForm: React.FC<UpdateUserContactsFormProps> = ({ contact
<Box> <Box>
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
<Box boxShadow='sm' borderRadius='sm' borderWidth='1px' padding='20px'> <Box boxShadow='sm' borderRadius='sm' borderWidth='1px' padding='20px'>
<Heading as='h3' size='lg'> <Heading as='h3' size='md'>
My Contacts My Contacts
</Heading> </Heading>
<Stack spacing='5px' margin='20px 0'> <Stack spacing='5px' margin='20px 0'>

View File

@ -12,7 +12,7 @@ const UserAccountInfo: React.FC<UserAccountInfoPropsType> = ({ user }) => {
return ( return (
<Box borderRadius='md' borderWidth='1px' padding='20px' boxShadow='sm'> <Box borderRadius='md' borderWidth='1px' padding='20px' boxShadow='sm'>
<Heading as='h3' size='lg'> <Heading as='h3' size='md'>
Account information Account information
</Heading> </Heading>
<Stack spacing='10px' mt='20px' divider={<StackDivider />}> <Stack spacing='10px' mt='20px' divider={<StackDivider />}>