feat: lesson progress

This commit is contained in:
Sergey Yarkov 2021-12-22 22:09:47 +03:00
parent 37c5d8c36e
commit c0fda55e5d
5 changed files with 73 additions and 15 deletions

View File

@ -0,0 +1,22 @@
import { LessonServiceInstance } from '@educt/services';
import type { LessonProgress } from '@educt/types';
import useAsync from '../../useAsync';
const useFetchLessonProgress = () => {
const fetch = async (id: string) => {
try {
const result = await LessonServiceInstance.fetchProgress(id);
return result.data;
} catch (error) {
console.error(error);
return Promise.reject(error);
}
};
const { execute, ...state } = useAsync<LessonProgress, Parameters<typeof fetch>>(fetch);
return { fetchLessonProgress: execute, ...state };
};
export { useFetchLessonProgress };

View File

@ -1,5 +1,5 @@
import type { RouteComponentProps } from 'react-router-dom'; import type { RouteComponentProps } from 'react-router-dom';
import { AttachmentFileType, ColorType, LinkType } from '@educt/types'; import { AttachmentFileType, ColorType, LessonProgress, LinkType } from '@educt/types';
import { CourseStatusEnum, UserRoleEnum } from '../enums'; import { CourseStatusEnum, UserRoleEnum } from '../enums';
export interface IAppConfig { export interface IAppConfig {
@ -27,7 +27,7 @@ export interface ICourse {
status: CourseStatusEnum; status: CourseStatusEnum;
teacher: Pick<IUser, 'id' | 'first_name' | 'fullname' | 'last_name' | 'email' | 'created_at' | 'updated_at'>; teacher: Pick<IUser, 'id' | 'first_name' | 'fullname' | 'last_name' | 'email' | 'created_at' | 'updated_at'>;
category: ICategory; category: ICategory;
lessons: Omit<ILesson, 'materials' | 'content'>[]; lessons: Omit<ILesson, 'materials' | 'content' | 'progress'>[];
students: IUser[]; students: IUser[];
color: ColorType | null; color: ColorType | null;
students_count: string; students_count: string;
@ -46,6 +46,7 @@ export interface ILesson {
color?: ColorType | undefined | null; color?: ColorType | undefined | null;
materials_count?: string | undefined; materials_count?: string | undefined;
materials: Array<ILessonMaterial>; materials: Array<ILessonMaterial>;
progress: LessonProgress;
content: ILessonContent; content: ILessonContent;
created_at: string; created_at: string;
updated_at: string; updated_at: string;

View File

@ -1,7 +1,8 @@
import React, { useEffect, useRef, useState } from 'react'; import React from 'react';
import moment from 'moment'; import moment from 'moment';
import * as helpres from '@educt/helpers'; import * as helpres from '@educt/helpers';
import { Link as ReactRouterLink, useHistory } from 'react-router-dom'; import { Link as ReactRouterLink, Redirect } from 'react-router-dom';
import { Helmet } from 'react-helmet';
import { import {
Flex, Flex,
Box, Box,
@ -18,6 +19,9 @@ import {
IconButton, IconButton,
useColorModeValue, useColorModeValue,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { MdOutlineCircle, MdCheckCircle, MdOutlineFilePresent, MdSkipNext, MdSkipPrevious } from 'react-icons/md';
import LoadingPage from '@educt/components/LoadingPage';
import { PageContent, PageHeading, PageWrapper } from '@educt/components/PageElements';
/** /**
* Types * Types
@ -27,13 +31,15 @@ import { ILesson, ILessonMaterial, IPageProps } from '@educt/interfaces';
/** /**
* Hooks * Hooks
*/ */
import { Redirect, useParams } from 'react-router-dom'; import { useEffect, useRef, useState } from 'react';
import { PageContent, PageHeading, PageWrapper } from '@educt/components/PageElements'; import { useHistory, useParams } from 'react-router-dom';
import { useFetchLesson } from '@educt/hooks/queries/lesson/useFetchLesson'; import { useFetchLesson } from '@educt/hooks/queries/lesson/useFetchLesson';
import LoadingPage from '@educt/components/LoadingPage';
import { MdOutlineCircle, MdOutlineFilePresent, MdSkipNext, MdSkipPrevious } from 'react-icons/md';
import { Helmet } from 'react-helmet';
import { useFetchCourseLessons } from '@educt/hooks/queries/course/useFetchCourseLessons'; import { useFetchCourseLessons } from '@educt/hooks/queries/course/useFetchCourseLessons';
import { useFetchLessonProgress } from '@educt/hooks/queries/lesson/useFetchLessonProgress';
/**
* Services
*/
import { LessonServiceInstance } from '@educt/services'; import { LessonServiceInstance } from '@educt/services';
/** /**
@ -43,6 +49,7 @@ const LessonPage: React.FC<IPageProps> = () => {
const { id } = useParams<{ id: string }>(); const { id } = useParams<{ id: string }>();
const { error, data: lesson, isLoading } = useFetchLesson(id); const { error, data: lesson, isLoading } = useFetchLesson(id);
const { fetchCourseLessons, data: lessons } = useFetchCourseLessons(); const { fetchCourseLessons, data: lessons } = useFetchCourseLessons();
const { fetchLessonProgress } = useFetchLessonProgress();
const history = useHistory(); const history = useHistory();
const [nextLesson, setNextLesson] = useState<ILesson | null>(null); const [nextLesson, setNextLesson] = useState<ILesson | null>(null);
const [prevLesson, setPrevLesson] = useState<ILesson | null>(null); const [prevLesson, setPrevLesson] = useState<ILesson | null>(null);
@ -66,7 +73,10 @@ const LessonPage: React.FC<IPageProps> = () => {
useEffect(() => { useEffect(() => {
if (lesson !== null) { if (lesson !== null) {
fetchCourseLessons(lesson.course_id); (async () => {
await fetchCourseLessons(lesson.course_id);
await fetchLessonProgress(lesson.id);
})();
} }
}, [lesson]); }, [lesson]);
@ -154,15 +164,20 @@ const LessonPage: React.FC<IPageProps> = () => {
ref={lesson.id === id ? currentLessonRef : undefined} ref={lesson.id === id ? currentLessonRef : undefined}
as='div' as='div'
display={'flex'} display={'flex'}
minH='100'
key={lesson.id} key={lesson.id}
bg={lesson.id === id ? bg : ''} bg={lesson.id === id ? bg : ''}
p='4' p='4'
alignItems={'center'} alignItems={'center'}
_hover={{ _hover={{ bg }}
bg,
}}
> >
<Icon as={MdOutlineCircle} color='gray.500' w={6} h={6} mr='2' /> <Icon
as={lesson.progress ? MdCheckCircle : MdOutlineCircle}
color={lesson.progress ? 'green.500' : 'gray.500'}
w={6}
h={6}
mr='2'
/>
<Box> <Box>
<Text as='small' color='gray.500'> <Text as='small' color='gray.500'>
Lesson {i + 1} Lesson {i + 1}
@ -204,7 +219,9 @@ const LessonPage: React.FC<IPageProps> = () => {
> >
{material.client_name} {material.client_name}
<br /> <br />
<Text as='small'>{helpres.transformBytes(material.size)}</Text> <Text as='small' color='gray.500'>
{helpres.transformBytes(material.size)}
</Text>
</Text> </Text>
</Flex> </Flex>
))} ))}

View File

@ -1,6 +1,7 @@
import { AxiosInstance } from 'axios'; import { AxiosInstance } from 'axios';
import { IApiRespose, ILesson } from '@educt/interfaces'; import { IApiRespose, ILesson } from '@educt/interfaces';
import { ApiServiceInstance } from './ApiService'; import { ApiServiceInstance } from './ApiService';
import type { LessonProgress } from '@educt/types';
class LessonService { class LessonService {
public api: AxiosInstance; public api: AxiosInstance;
@ -31,6 +32,17 @@ class LessonService {
return result.data; return result.data;
} }
/**
* Get progress about lesson
*
* @param id Lesson id
* @returns Progress info
*/
public async fetchProgress(id: string): Promise<IApiRespose<LessonProgress>> {
const result = await this.api.get(`/v1/lessons/${id}/progress`);
return result.data;
}
/** /**
* Delete lesson by id * Delete lesson by id
* *

View File

@ -34,6 +34,12 @@ export type ColorType = {
hex: string; hex: string;
}; };
export type LessonProgress = {
progress: {
is_watched: boolean;
} | null;
};
export type ConfirmEmailContainerDataType = { export type ConfirmEmailContainerDataType = {
newEmail: string; newEmail: string;
expired_seconds: number; expired_seconds: number;