diff --git a/package-lock.json b/package-lock.json index 2bcda27..ab1fdf9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1072,9 +1072,9 @@ } }, "@hookform/resolvers": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-2.8.2.tgz", - "integrity": "sha512-oDTGrm7yHxT4VIv4kJcfjvWvozCbdcL0/jrpbAkeo39FYn78XnKOrrGTNmrXdfu+EQVkNIdZ47IYRFManZ4jUA==" + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-2.8.5.tgz", + "integrity": "sha512-n7eFm4snsejpfZVH8q2NU7YJbsGhF61IHB0TxgK11nmg08RymEr3KscnbTAZaPd9RaXa3vUPoULgBRN2nVDtMg==" }, "@humanwhocodes/config-array": { "version": "0.9.2", @@ -3320,9 +3320,9 @@ } }, "react-hook-form": { - "version": "7.17.4", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.17.4.tgz", - "integrity": "sha512-7XhbCr7d9fDC1TgcK/BUbt7D3q0VJMu7jPErfsa0JrxVjv/nni41xWdJcy0Zb7R+Np8OsCkQ2lMyloAtE3DLiQ==" + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.22.5.tgz", + "integrity": "sha512-Q2zaeQFXdVQ8l3hcywhltH+Nzj4vo50wMVujHDVN/1Xy9IOaSZJwYBXA2CYTpK6rq41fnXviw3jTLb04c7Gu9Q==" }, "react-icons": { "version": "4.3.1", diff --git a/package.json b/package.json index fad5354..45caf72 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "@chakra-ui/react": "^1.6.10", "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@hookform/resolvers": "^2.8.0", + "@hookform/resolvers": "^2.8.5", "axios": "^0.21.1", "framer-motion": "^4.0.0", "js-cookie": "^3.0.0", @@ -26,7 +26,7 @@ "react-dom": "^17.0.0", "react-error-boundary": "^3.1.3", "react-helmet": "^6.1.0", - "react-hook-form": "^7.12.2", + "react-hook-form": "^7.22.5", "react-icons": "^4.3.1", "react-player": "^2.9.0", "react-router-dom": "^5.2.0", diff --git a/src/components/Forms/LessonForm/CreateLessonForm.tsx b/src/components/Forms/LessonForm/CreateLessonForm.tsx index 4b9a8bb..c55e609 100644 --- a/src/components/Forms/LessonForm/CreateLessonForm.tsx +++ b/src/components/Forms/LessonForm/CreateLessonForm.tsx @@ -2,20 +2,33 @@ import { yupResolver } from '@hookform/resolvers/yup'; import React from 'react'; import { SubmitHandler, useForm } from 'react-hook-form'; import { LessonForm } from '.'; -import { InputFields } from './LessonForm'; +import type { InputFields } from './LessonForm'; import LessonFormSchema from './LessonForm.validator'; +import { useCreateLesson } from '@educt/hooks/queries'; +import { useHistory, useParams } from 'react-router-dom'; const CreateLessonForm: React.FC = () => { const form = useForm({ resolver: yupResolver(LessonFormSchema) }); + const { createLesson, isLoading } = useCreateLesson(); + const { id: course_id } = useParams<{ id: string }>(); + const history = useHistory(); const onSubmit: SubmitHandler = async data => { - console.log('creating...'); - console.log(data); + const lesson = await createLesson({ + title: data.title, + description: data.description, + duration: data.duration, + video: data.video, + materials: Array.from(data.materials || []), + course_id, + }); + console.log(`created: ${lesson}`); + history.push(`/courses/edit/${course_id}`); }; return ( = ({ onSubmit, buttonLabel, isLo control={control} name='materials' render={({ field: { onChange, value: files } }) => ( - onChange(files)} files={files} /> + onChange(files)} files={Array.from(files || [])} /> )} /> diff --git a/src/components/Forms/LessonForm/LessonForm.validator.ts b/src/components/Forms/LessonForm/LessonForm.validator.ts index b901a56..04fc076 100644 --- a/src/components/Forms/LessonForm/LessonForm.validator.ts +++ b/src/components/Forms/LessonForm/LessonForm.validator.ts @@ -4,35 +4,37 @@ import yup from '@educt/schema'; const VIDEO_FILE_SIZE = 5000 * 1024 * 1024; const MATERIAL_FILE_SIZE = 100000 * 1024; -const LessonFormSchema = yup.object().shape({ - title: yup.string().required('Title field name is required').max(90, 'Title must be at most 90 characters'), - description: yup - .string() - .required('Description field name is required') - .max(250, 'Description must be at most 250 characters'), - duration: yup.string().required('Duration field name is required'), - video: yup - .mixed() - .test( - 'fileSize', - `File size is too large, maximum size is ${helpers.transformBytes(VIDEO_FILE_SIZE)}`, - (value: File) => { - if (!value) return true; - return value && value.size <= VIDEO_FILE_SIZE; - } - ) - .required('Video field name is required'), - materials: yup - .mixed() - .test( - 'fileSize', - `File size is too large, maximum size is ${helpers.transformBytes(MATERIAL_FILE_SIZE)}`, - (values: File[]) => { - if (!values) return true; - return values && values.every(value => value.size <= MATERIAL_FILE_SIZE); - } - ) - .optional(), -}); +const LessonFormSchema = yup + .object({ + title: yup.string().required('Title field name is required').max(90, 'Title must be at most 90 characters'), + description: yup + .string() + .required('Description field name is required') + .max(250, 'Description must be at most 250 characters'), + duration: yup.string().required('Duration field name is required'), + video: yup + .mixed() + .test( + 'fileSize', + `File size is too large, maximum size is ${helpers.transformBytes(VIDEO_FILE_SIZE)}`, + (value: File) => { + if (!value) return true; + return value && value.size <= VIDEO_FILE_SIZE; + } + ) + .required('Video field name is required'), + materials: yup + .mixed() + .test( + 'fileSize', + `File size is too large, maximum size is ${helpers.transformBytes(MATERIAL_FILE_SIZE)}`, + (values: File[]) => { + if (!values) return true; + return values && values.every(value => value.size <= MATERIAL_FILE_SIZE); + } + ) + .optional(), + }) + .required(); export default LessonFormSchema; diff --git a/src/hooks/queries/index.ts b/src/hooks/queries/index.ts index e2fefcb..d04c902 100644 --- a/src/hooks/queries/index.ts +++ b/src/hooks/queries/index.ts @@ -7,6 +7,7 @@ import { useLogout } from './auth/useLogout'; /** * Lesson */ +import { useCreateLesson } from './lesson/useCreateLesson'; import { useDeleteLesson } from './lesson/useDeleteLesson'; /** @@ -36,6 +37,7 @@ export { useSetCourseStatus, useAttachStudents, useDetachStudents, + useCreateLesson, useDeleteLesson, useCreateUser, useDeleteUser, diff --git a/src/hooks/queries/lesson/useCreateLesson.ts b/src/hooks/queries/lesson/useCreateLesson.ts new file mode 100644 index 0000000..b58dec3 --- /dev/null +++ b/src/hooks/queries/lesson/useCreateLesson.ts @@ -0,0 +1,45 @@ +import axios from 'axios'; +import { ILesson } from '@educt/interfaces'; +import { LessonServiceInstance } from '@educt/services'; +import type { CreateLessonParamsType } from '@educt/types'; +import useAsync from '@educt/hooks/useAsync'; +import { useErrorHandler } from 'react-error-boundary'; +import { useToast } from '@chakra-ui/react'; + +const useCreateLesson = () => { + const toast = useToast(); + const handleError = useErrorHandler(); + + const createLesson = async (data: CreateLessonParamsType) => { + try { + const result = await LessonServiceInstance.create(data); + toast({ title: `Lesson successfully created.`, status: 'success' }); + return result.data; + } catch (error: unknown) { + if (axios.isAxiosError(error)) { + if (error.response) { + switch (error.response.status) { + case 422: + toast({ title: `${error.response.data.errors[0].message}`, status: 'error' }); + break; + default: + toast({ title: `${error.message}`, status: 'error' }); + break; + } + } else { + handleError(error); + } + } else { + handleError(error); + } + + return Promise.reject(error); + } + }; + + const { execute, ...state } = useAsync>(createLesson); + + return { createLesson: execute, ...state }; +}; + +export { useCreateLesson }; diff --git a/src/services/LessonService.ts b/src/services/LessonService.ts index b1bfbec..902fed1 100644 --- a/src/services/LessonService.ts +++ b/src/services/LessonService.ts @@ -1,4 +1,5 @@ import { AxiosInstance } from 'axios'; +import * as helpers from '@educt/helpers'; import { IApiRespose, ILesson } from '@educt/interfaces'; import { ApiServiceInstance } from './ApiService'; import type { CreateLessonParamsType, LessonProgress } from '@educt/types'; @@ -49,7 +50,8 @@ class LessonService { * @param data Lesson data for creating */ public async create(data: CreateLessonParamsType): Promise> { - console.log(data); + const result = await this.api.post(`/v1/lessons`, helpers.transformToFormData(data)); + return result.data; } /**