From 65faa4de5f555a39149dc4c9f0ca372dd265aa49 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Thu, 13 Feb 2025 10:58:22 +0330 Subject: [PATCH] learning --- src/components/UploadBoxDraggble.tsx | 34 +++- src/langs/fa.json | 13 +- src/pages/learning/Create.tsx | 167 ++++++++++++++++++ src/pages/learning/List.tsx | 166 +++++++---------- .../components/CreateLearningSidebar.tsx | 40 +++++ src/pages/learning/hooks/useLearningData.ts | 19 +- src/pages/learning/service/LearningService.ts | 15 +- src/pages/learning/types/LearningTypes.ts | 26 +++ src/router/Main.tsx | 2 + 9 files changed, 365 insertions(+), 117 deletions(-) create mode 100644 src/pages/learning/Create.tsx create mode 100644 src/pages/learning/components/CreateLearningSidebar.tsx diff --git a/src/components/UploadBoxDraggble.tsx b/src/components/UploadBoxDraggble.tsx index 3659fc7..53215a0 100644 --- a/src/components/UploadBoxDraggble.tsx +++ b/src/components/UploadBoxDraggble.tsx @@ -7,6 +7,7 @@ type Props = { label: string; onChange: (file: File[]) => void; isMultiple?: boolean; + isFile?: boolean, } const UploadBoxDraggble: FC = (props: Props) => { @@ -60,16 +61,31 @@ const UploadBoxDraggble: FC = (props: Props) => { files.length > 0 && (
{ - files.map((file, index) => ( -
-
- {file.name} -
- handleDelete(index)} className='size-4 ' color='red' /> + files.map((file, index) => { + if (props.isFile) { + return ( +
+
+
{file.name}
+
+ handleDelete(index)} className='size-4 ' color='red' /> +
+
-
-
- )) + ) + } + else + return ( +
+
+ {file.name} +
+ handleDelete(index)} className='size-4 ' color='red' /> +
+
+
+ ) + }) }
) diff --git a/src/langs/fa.json b/src/langs/fa.json index a5e9ca7..42f8c7c 100644 --- a/src/langs/fa.json +++ b/src/langs/fa.json @@ -428,7 +428,18 @@ "learning": "آموزش", "learnings": "آموزش ها", "new_learning": "افزودن آموزش", - "category_learning": "دسته بندی آموزش" + "category_learning": "دسته بندی آموزش", + "submit_learning": "ثبت آموزش", + "title": "عنوان آموزش", + "category": "دسته بندی", + "description": "توضیحات", + "video_duration": "مدت زمان ویدیو", + "learning_cover": "کاور آموزش", + "upload_cover": "آپلود کاور", + "video": "آپلود ویدیو", + "upload_video": "آپلود ویدیو", + "error_video_cover_required": "آپلود ویدیو و کاور اجباری است", + "list_learning": "لیست آموزش ها" }, "setting": { "setting": "تنظیمات", diff --git a/src/pages/learning/Create.tsx b/src/pages/learning/Create.tsx new file mode 100644 index 0000000..2a0b193 --- /dev/null +++ b/src/pages/learning/Create.tsx @@ -0,0 +1,167 @@ +import { FC, useState } from 'react' +import { useTranslation } from 'react-i18next' +import Button from '../../components/Button' +import { useFormik } from 'formik' +import { CategoryLearningType, CreateLearningType } from './types/LearningTypes' +import * as Yup from 'yup' +import { useCreateLearning, useGetCategory } from './hooks/useLearningData' +import { useSingleUpload } from '../service/hooks/useServiceData' +import { TickCircle } from 'iconsax-react' +import Input from '../../components/Input' +import Select from '../../components/Select' +import Textarea from '../../components/Textarea' +import PageLoading from '../../components/PageLoading' +import CreateLearningSidebar from './components/CreateLearningSidebar' +import { ErrorType } from '../../helpers/types' +import { toast } from 'react-toastify' +import { useNavigate } from 'react-router-dom' +import { Pages } from '../../config/Pages' + +const CreateLearning: FC = () => { + + const navigate = useNavigate() + const { t } = useTranslation('global') + const singleUpload = useSingleUpload() + const createLearning = useCreateLearning() + const getCategory = useGetCategory() + const [videoFile, setVideoFile] = useState() + const [coverFile, setCoverFile] = useState() + + const formik = useFormik({ + initialValues: { + title: '', + description: '', + coverUrl: '', + videoUrl: '', + videoDuration: '', + categoryId: '' + }, + validationSchema: Yup.object().shape({ + title: Yup.string().required(t('errors.required')), + description: Yup.string().required(t('errors.required')), + videoDuration: Yup.string().required(t('errors.required')), + categoryId: Yup.string().required(t('errors.required')) + }), + onSubmit: async (values) => { + if (videoFile && coverFile) { + + const formData = new FormData() + formData.append('file', videoFile) + await singleUpload.mutateAsync(formData, { + onSuccess: (data) => { + values.videoUrl = data?.data?.url + }, + onError: (error: ErrorType) => { + toast.error(error.response?.data?.error?.message[0]) + } + }) + + const formDataCover = new FormData() + formDataCover.append('file', coverFile) + await singleUpload.mutateAsync(formDataCover, { + onSuccess: (data) => { + values.coverUrl = data?.data?.url + }, + onError: (error: ErrorType) => { + toast.error(error.response?.data?.error?.message[0]) + } + }) + + createLearning.mutate(values, { + onSuccess: () => { + toast.success(t('success')) + navigate(Pages.learning.list) + }, + onError: (error: ErrorType) => { + toast.error(error.response?.data?.error?.message[0]) + } + }) + } else { + toast.error(t('learning.error_video_cover_required')) + } + } + }) + + return ( +
+
+
+ {t('learning.new_learning')} +
+
+ +
+
+ + { + getCategory.isPending ? + + : +
+
+
+ + + +
+ +
+ +
+
{t('learning.description')}
+
+