mirror of
https://github.com/sergeyyarkov/educt-client.git
synced 2026-10-11 10:19:22 +03:00
feat: lesson progress
This commit is contained in:
parent
37c5d8c36e
commit
c0fda55e5d
22
src/hooks/queries/lesson/useFetchLessonProgress.ts
Normal file
22
src/hooks/queries/lesson/useFetchLessonProgress.ts
Normal 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 };
|
||||||
@ -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;
|
||||||
|
|||||||
@ -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>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -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
|
||||||
*
|
*
|
||||||
|
|||||||
6
src/types/index.d.ts
vendored
6
src/types/index.d.ts
vendored
@ -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;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user