From 962e43c81c873fb740c1331af2b0bf57c7ab1900 Mon Sep 17 00:00:00 2001 From: Sergey Yarkov Date: Tue, 12 Oct 2021 21:18:11 +0300 Subject: [PATCH] feat: render courses by selected categoru --- .../components/CategoryList/CategoryList.tsx | 15 +++++++++--- .../components/CourseList/CourseList.tsx | 10 ++++++-- .../CourseList/CourseListLoading.tsx | 10 ++++---- src/pages/courses/index.tsx | 23 +++++------------- src/services/CourseService.ts | 24 +++++++++++++++++-- src/stores/CategoryStore.ts | 9 +++++++ src/stores/CourseStore.ts | 15 +++++++++--- 7 files changed, 73 insertions(+), 33 deletions(-) diff --git a/src/pages/courses/components/CategoryList/CategoryList.tsx b/src/pages/courses/components/CategoryList/CategoryList.tsx index 6bb3735..6952720 100644 --- a/src/pages/courses/components/CategoryList/CategoryList.tsx +++ b/src/pages/courses/components/CategoryList/CategoryList.tsx @@ -3,12 +3,16 @@ import { Box, Flex, Tag, TagLabel } from '@chakra-ui/react'; import { CoursesPageContext } from 'contexts'; import CategoryItem from './CategoryItem'; import { ICategory } from 'interfaces'; +import CategoryListLoading from './CategoryListLoading'; +import { useRootStore } from 'hooks/useRootStore'; type CategoryListPropsType = { - categories: ICategory[]; + categories: ICategory[] | null; + isLoading: boolean; }; -const CategoryList: React.FC = ({ categories }) => { +const CategoryList: React.FC = ({ categories, isLoading }) => { + const { courseStore } = useRootStore(); const { selectedCategory, setSelectedCategory } = useContext(CoursesPageContext); /** @@ -16,7 +20,12 @@ const CategoryList: React.FC = ({ categories }) => { */ useEffect(() => { console.log(`[LOG:] Selected category: ${selectedCategory?.title}`); - }, [selectedCategory]); + courseStore.loadCourses({ category_id: selectedCategory?.id }); + }, [courseStore, selectedCategory]); + + if (isLoading || categories === null) { + return ; + } return ( diff --git a/src/pages/courses/components/CourseList/CourseList.tsx b/src/pages/courses/components/CourseList/CourseList.tsx index 8fee619..d1d8648 100644 --- a/src/pages/courses/components/CourseList/CourseList.tsx +++ b/src/pages/courses/components/CourseList/CourseList.tsx @@ -10,12 +10,18 @@ import { ICourse } from 'interfaces'; * Components */ import CourseItem from './CourseItem'; +import CourseListLoading from './CourseListLoading'; type CourseListPropsType = { - courses: Omit[]; + courses: Omit[] | null; + isLoading: boolean; }; -const CourseList: React.FC = ({ courses }) => { +const CourseList: React.FC = ({ courses, isLoading }) => { + if (isLoading || courses === null) { + return ; + } + return ( { return ( - - - - - + + Wait a second... + ); }; diff --git a/src/pages/courses/index.tsx b/src/pages/courses/index.tsx index 968f2f2..48c567c 100644 --- a/src/pages/courses/index.tsx +++ b/src/pages/courses/index.tsx @@ -17,8 +17,7 @@ import CategoryList from './components/CategoryList'; import { useRootStore } from 'hooks/useRootStore'; import { CoursesPageContextProvider } from 'providers'; import { useErrorHandler } from 'react-error-boundary'; -import CategoryListLoading from './components/CategoryList/CategoryListLoading'; -import CourseListLoading from './components/CourseList/CourseListLoading'; +import LoadingPage from 'components/LoadingPage'; /** * Courses page @@ -34,14 +33,11 @@ const CoursesPage: React.FC = ({ title }) => { useEffect(() => { if (me !== null) { categoryStore.loadCategories().catch(error => handleError(error)); - courseStore.loadCourses().catch(error => handleError(error)); + // courseStore.loadCourses().catch(error => handleError(error)); } - }, [me, categoryStore, courseStore, handleError]); + }, [me, categoryStore, handleError]); - /** - * TODO: Loading page for courses - */ - if (me === null) return null; + if (me === null) return ; return ( @@ -68,15 +64,8 @@ const CoursesPage: React.FC = ({ title }) => { )} - {/* Category List Rendering */} - {categoryStore.categories !== null ? ( - - ) : ( - - )} - - {/* Course List Rendering */} - {courseStore.courses !== null ? : } + + diff --git a/src/services/CourseService.ts b/src/services/CourseService.ts index f4fde02..5916911 100644 --- a/src/services/CourseService.ts +++ b/src/services/CourseService.ts @@ -1,6 +1,19 @@ import { AxiosInstance } from 'axios'; +import { CourseStatusEnum } from 'enums'; import { IApiRespose, ICourse } from 'interfaces'; +export type FetchCoursesParams = { + /** + * Get courses by status + */ + status?: CourseStatusEnum; + + /** + * Get courses with category by id + */ + category_id?: string; +}; + export class CourseService { public api: AxiosInstance; @@ -13,8 +26,15 @@ export class CourseService { * * @returns Array of courses */ - public async fetchAll(): Promise[]>> { - const result = await this.api.get('/v1/courses'); + public async fetchAll( + params?: FetchCoursesParams + ): Promise[]>> { + const result = await this.api.get('/v1/courses', { + params: { + status: params?.status, + category_id: params?.category_id, + }, + }); return result.data; } } diff --git a/src/stores/CategoryStore.ts b/src/stores/CategoryStore.ts index f86c09b..4f3420d 100644 --- a/src/stores/CategoryStore.ts +++ b/src/stores/CategoryStore.ts @@ -11,14 +11,21 @@ export default class CategoryStore { public categories: ICategory[] | null = null; + public isLoading: boolean = false; + constructor(root: RootStore, api: AxiosInstance) { this.root = root; this.categoryService = new CategoryService(api); makeAutoObservable(this); } + public setLoading(loading: boolean) { + this.isLoading = loading; + } + public async loadCategories() { try { + this.setLoading(true); const result = await this.categoryService.fetchAll(); console.log(`[${this.constructor.name}]: ${result.message}`, result); @@ -29,6 +36,8 @@ export default class CategoryStore { return result; } catch (error: any) { throw error; + } finally { + this.setLoading(false); } } } diff --git a/src/stores/CourseStore.ts b/src/stores/CourseStore.ts index eff9daa..99499c9 100644 --- a/src/stores/CourseStore.ts +++ b/src/stores/CourseStore.ts @@ -1,7 +1,7 @@ import { AxiosInstance } from 'axios'; import { ICourse } from 'interfaces'; import { makeAutoObservable, runInAction } from 'mobx'; -import { CourseService } from 'services/CourseService'; +import { CourseService, FetchCoursesParams } from 'services/CourseService'; import RootStore from './RootStore'; export default class CourseStore { @@ -11,15 +11,22 @@ export default class CourseStore { public courses: Omit[] | null = null; + public isLoading: boolean = false; + constructor(root: RootStore, api: AxiosInstance) { this.root = root; this.courseService = new CourseService(api); makeAutoObservable(this); } - public async loadCourses() { + public setLoading(loading: boolean) { + this.isLoading = loading; + } + + public async loadCourses(params?: FetchCoursesParams) { try { - const result = await this.courseService.fetchAll(); + this.setLoading(true); + const result = await this.courseService.fetchAll(params); console.log(`[${this.constructor.name}]: ${result.message}`, result); runInAction(() => { @@ -29,6 +36,8 @@ export default class CourseStore { return result; } catch (error: any) { throw error; + } finally { + this.setLoading(false); } } }