diff --git a/src/components/modals/material.tsx b/src/components/modals/material.tsx index 8bf7a8a751f23cb9f5e1a3ab24f7fca7df0be370..28de400cdd88e080037b1e858caae4590e4763c1 100644 --- a/src/components/modals/material.tsx +++ b/src/components/modals/material.tsx @@ -1,211 +1,599 @@ -import { Box, Text, Modal, ModalOverlay, ModalContent, ModalHeader, ModalCloseButton, ModalBody, FormControl, FormLabel, Input, Textarea, ModalFooter, ButtonGroup, Button } from "@chakra-ui/react"; +import { + Box, + Text, + Modal, + ModalOverlay, + ModalContent, + ModalHeader, + ModalCloseButton, + ModalBody, + FormControl, + FormLabel, + Input, + Textarea, + ModalFooter, + ButtonGroup, + Button, +} from "@chakra-ui/react"; +import { ChangeEvent, createRef, useEffect, useState } from "react"; import { BiError } from "react-icons/bi"; +import { axiosConfig } from "../../utils/axios"; +import axios from "axios"; +import config from "../../config/config"; +import Loading from "../loading/Loading"; -{ /* Modal Edit */ } -interface EditMaterialModalProps { +{/* Modal Add Material*/ } +interface AddMaterialModalProps { isOpen: boolean; onClose: () => void; - title: string; - description: string; - handleEdit: () => void; + successAdd: () => void; + moduleId: number; } -export function EditMaterialModal({ +export function AddMaterialModal({ isOpen, onClose, - title, - description, - handleEdit, -}: EditMaterialModalProps) { + successAdd, + moduleId, +}: AddMaterialModalProps) { + const [title, setTitle] = useState(""); + const [description, setDescription] = useState(""); + const [isLoading, setIsLoading] = useState(false); + const newAxiosInstance = axios.create(axiosConfig()); + const [fileType, setFileType] = useState(""); + const [fileName, setFileName] = useState(""); + const [selectedFile, setSelectedFile] = useState<File | null>(null); + const [isAllValid, setIsAllValid] = useState({ + title: false, + description: false, + file: false, + }); + const handleAddMaterial = async () => { + try { + setIsLoading(true); + try { + upload(); + } catch (error) { + console.error('Error uploading:', error); + } finally { + const response = await newAxiosInstance.post(`${config.REST_API_URL}/material/`, { + title: title, + description: description, + source_type: fileType, + material_path: fileName, + modul_id: moduleId, + }); + + console.log('Material added successfully:', response.data.message); + + // Clear the form after successful submission if needed + setTitle(''); + setDescription(''); + setIsLoading(false); + successAdd(); // Refresh new data without reloading page + } + } catch (error) { + console.error('Error adding material:', error); + } finally { + setIsAllValid(prevState => ({ + ...prevState, + title: false, + description: false, + file: false, + })); + } + // window.location.reload(); // refresh to see new material added (should change to not reloading) + }; + + const upload = () => { + const formData = new FormData() + if (selectedFile) { + formData.append('file', selectedFile) + } + newAxiosInstance.post(`${config.REST_API_URL}/material/upload`, formData) + .then(res => { }) + .catch(er => console.log(er)) + } + + const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => { + if (event.target.files) { + const file = event.target.files?.[0]; + + if (file) { + // const name = file.name; + // const type = file.type; + setSelectedFile(file); + if (file.type.startsWith('video')) { + setFileType('VIDEO'); + } else { + setFileType('PDF'); + } + + setFileName(file.name.replace(/\s/g, '')); + + setIsAllValid({ ...isAllValid, file: true }); + } else { + setIsAllValid({ ...isAllValid, file: false }); + } + } else { + setSelectedFile(null); + setIsAllValid({ ...isAllValid, file: false }); + } + }; + + const handleClose = () => { + setTitle(""); + setDescription(""); + setIsAllValid(prevState => ({ + ...prevState, + title: false, + description: false, + file: false, + })); + onClose(); + }; + + const checkTitle = () => { + setTitle((prevTitle) => { + const isValid = prevTitle.trim().length > 0; + setIsAllValid((prev) => ({ ...prev, title: isValid })); + return prevTitle; + }); + }; + + const checkDescription = () => { + setDescription((prevDescription) => { + const isValid = prevDescription.trim().length > 0; + setIsAllValid((prev) => ({ ...prev, description: isValid })); + return prevDescription; + }); + }; + + const handleTitleChange = (e: React.ChangeEvent<HTMLInputElement>) => { + setTitle(e.target.value); + checkTitle(); + }; + + const handleDescriptionChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => { + setDescription(e.target.value); + checkDescription(); + }; + return ( - <Modal isOpen={isOpen} onClose={onClose}> - <ModalOverlay /> - <ModalContent> - <ModalHeader bg="#d78dff" textAlign={"center"}> - Edit Material - </ModalHeader> - <ModalCloseButton /> - <ModalBody> - <FormControl> - <FormLabel ms="4px" fontSize="sm" fontWeight="bold"> - Material Title - </FormLabel> - <Input - isRequired - variant="outline" - bg="white" - borderRadius="15px" - mb="5" - fontSize="sm" - placeholder={title} - size="lg" - /> - - <FormLabel ms="4px" fontSize="sm" fontWeight="bold"> - Material Description - </FormLabel> - <Textarea - isRequired - h="50" - maxHeight={"150"} - bg="white" - borderRadius="15px" - mb="5" - fontSize="sm" - placeholder={description} - size="lg" - /> - <FormLabel ms="4px" fontSize="sm" fontWeight="bold"> - Material File - </FormLabel> - <Input - fontSize="sm" - border="none" - type="file" - accept="image/*" - size="lg" - /> - </FormControl> - </ModalBody> - - <ModalFooter justifyContent={"center"}> - <ButtonGroup> - <Button colorScheme="gray" flex="1" onClick={onClose}> - Cancel - </Button> - <Button colorScheme="purple" flex="1" ml={3} onClick={handleEdit}> - Edit - </Button> - </ButtonGroup> - </ModalFooter> - </ModalContent> - </Modal> + <> + <Loading loading={isLoading} /> + <Modal isOpen={isOpen} onClose={handleClose}> + <ModalOverlay /> + <ModalContent> + <ModalHeader bg="#d78dff" textAlign={"center"}> + Add New Material + </ModalHeader> + <ModalCloseButton /> + <ModalBody> + <FormControl> + <FormLabel ms="4px" fontSize="sm" fontWeight="bold"> + Material Title + </FormLabel> + <Input + isRequired + variant="outline" + bg="white" + borderRadius="15px" + mb="5" + fontSize="sm" + size="lg" + placeholder={"Insert Title Here"} + value={title} + onChange={handleTitleChange} + /> + + <FormLabel ms="4px" fontSize="sm" fontWeight="bold"> + Material Description + </FormLabel> + <Textarea + isRequired + h="50" + maxHeight={"150"} + bg="white" + borderRadius="15px" + mb="5" + fontSize="sm" + size="lg" + placeholder={"Insert Description Here"} + value={description} + onChange={handleDescriptionChange} + /> + + <FormLabel ms="4px" fontSize="sm" fontWeight="bold"> + Material File + </FormLabel> + <Input + fontSize="sm" + border="none" + type="file" + accept=".pdf, video/*" + size="lg" + onChange={handleFileChange} + /> + </FormControl> + </ModalBody> + + <ModalFooter justifyContent={"center"}> + <ButtonGroup> + <Button colorScheme="gray" flex="1" onClick={handleClose}> + Cancel + </Button> + <Button colorScheme="purple" flex="1" ml={3} + onClick={handleAddMaterial} + isDisabled={ + !( + isAllValid.title && + isAllValid.description && + isAllValid.file + ) + } + > + Add + </Button> + </ButtonGroup> + </ModalFooter> + </ModalContent> + </Modal> + </> ); } -{ /* Modal Delete */ } -interface DeleteMaterialModalProps { +{ /* Modal Edit Material */ } +interface EditMaterialModalProps { isOpen: boolean; onClose: () => void; - course_id: number; - handleDelete: () => void; + successEdit: () => void; + materialId: number } -export function DeleteMaterialModal({ +export function EditMaterialModal({ isOpen, onClose, - course_id, - handleDelete, -}: DeleteMaterialModalProps) { + successEdit, + materialId, +}: EditMaterialModalProps) { + const [editedTitle, setEditedTitle] = useState(''); + const [editedDescription, setEditedDescription] = useState(''); + const [title, setTitle] = useState(''); + const [description, setDescription] = useState(''); + const [isLoading, setIsLoading] = useState(false); + const newAxiosInstance = axios.create(axiosConfig()); + const [selectedFile, setSelectedFile] = useState<File | null>(null); + const [fileType, setFileType] = useState(""); + const [fileName, setFileName] = useState(""); + const [oldFile, setOldFile] = useState(""); + const [isAllValid, setIsAllValid] = useState({ + title: false, + description: false, + file: false, + }); + + useEffect(() => { // Fetch Data to Get Material Detail + const fetchData = async () => { + try { + setIsLoading(true); + const res = await newAxiosInstance.get(`${config.REST_API_URL}/material/${materialId}`); + if (res.data.status === 200) { + setEditedTitle(res.data.data.title); + setEditedDescription(res.data.data.description); + setTitle(res.data.data.title); + setDescription(res.data.data.description); + setOldFile(res.data.data.material_path); + } else { } + setIsLoading(false); + } catch (error) { + console.error('Error fetching material data:', error); + } + }; + fetchData(); + }, [materialId]); + + const handleEditMaterial = async () => { + try { + setIsLoading(true); + try { + if (isAllValid.file) { + upload(); + } else { + setFileName(oldFile); + } + } catch (error) { + console.error('Error uploading:', error); + } finally { + const response = await newAxiosInstance.put(`${config.REST_API_URL}/material/${materialId}`, { + title: title, + description: description, + source_type: fileType, + material_path: fileName, + }); + + console.log('Material edited successfully:', response.data.message); + setIsLoading(false); + successEdit(); // Refresh new data without reloading page + } + } catch (error) { + console.error('Error editing material:', error); + } finally { + // window.location.reload(); // refresh to see new material added (should change to not reloading) + setIsAllValid(prevState => ({ + ...prevState, + title: false, + description: false, + file: false, + })); + } + }; + + const upload = () => { + const formData = new FormData() + if (oldFile) { + // Make a delete request to remove the old file + newAxiosInstance.delete(`${config.REST_API_URL}/material/deleteFile/${oldFile}`) + .then(() => { + console.log('Old file deleted successfully'); + }) + .catch((error) => { + console.error('Error deleting old file:', error); + }); + } + if (selectedFile) { + formData.append('file', selectedFile) + } + newAxiosInstance.post(`${config.REST_API_URL}/material/upload`, formData) + .then(res => { }) + .catch(er => console.log(er)) + } + + const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => { + if (event.target.files) { + const file = event.target.files?.[0]; + + if (file) { + // const name = file.name; + // const type = file.type; + setSelectedFile(file); + if (file.type.startsWith('video')) { + setFileType('VIDEO'); + } else { + setFileType('PDF'); + } + + setFileName(file.name.replace(/\s/g, '')); + + setIsAllValid({ ...isAllValid, file: true }); + } else { + setIsAllValid({ ...isAllValid, file: false }); + } + } else { + setSelectedFile(null); + setIsAllValid({ ...isAllValid, file: false }); + } + }; + + const handleClose = () => { + setTitle(editedTitle); + setDescription(editedDescription); + setIsAllValid(prevState => ({ + ...prevState, + title: false, + description: false, + file: false, + })); + onClose(); + }; + + const handleTitleChange = (e: React.ChangeEvent<HTMLInputElement>) => { + if (e.target.value.length > 0) { + setTitle(e.target.value); + setIsAllValid(prevState => ({ + ...prevState, + title: true, + })); + } else { + setTitle(editedTitle); + setIsAllValid(prevState => ({ + ...prevState, + title: false, + })); + } + }; + + const handleDescriptionChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => { + if (e.target.value.length > 0) { + setDescription(e.target.value); + setIsAllValid(prevState => ({ + ...prevState, + description: true, + })); + } else { + setDescription(editedDescription); + setIsAllValid(prevState => ({ + ...prevState, + description: false, + })); + } + }; + return ( - <Modal isOpen={isOpen} onClose={onClose}> - <ModalOverlay /> - <ModalContent> - <ModalHeader textAlign={"center"}>Delete Material</ModalHeader> - <ModalCloseButton /> - <ModalBody textAlign={"center"}> - <Box - display="flex" - flexDirection="column" - alignItems="center" - justifyContent="center" - > - <Text as={BiError} fontSize={"150px"} color="red" /> - <Text>Are you sure want to delete this Material?</Text> - </Box> - </ModalBody> - - <ModalFooter justifyContent={"center"}> - <ButtonGroup> - <Button colorScheme="gray" flex="1" onClick={onClose}> - Cancel - </Button> - <Button colorScheme="red" flex="1" ml={3} onClick={handleDelete}> - Delete - </Button> - </ButtonGroup> - </ModalFooter> - </ModalContent> - </Modal> + <> + <Loading loading={isLoading} /> + <Modal isOpen={isOpen} onClose={handleClose}> + <ModalOverlay /> + <ModalContent> + <ModalHeader bg="#d78dff" textAlign={"center"}> + Edit Material + </ModalHeader> + <ModalCloseButton /> + <ModalBody> + <FormControl> + <FormLabel ms="4px" fontSize="sm" fontWeight="bold"> + Material Title + </FormLabel> + <Input + isRequired + variant="outline" + bg="white" + borderRadius="15px" + mb="5" + fontSize="sm" + placeholder={title} + size="lg" + // value={editedTitle} + onChange={handleTitleChange} + /> + + <FormLabel ms="4px" fontSize="sm" fontWeight="bold"> + Material Description + </FormLabel> + <Textarea + isRequired + h="50" + maxHeight={"150"} + bg="white" + borderRadius="15px" + mb="5" + fontSize="sm" + placeholder={description} + size="lg" + // value={editedDescription} + onChange={handleDescriptionChange} + /> + + <FormLabel ms="4px" fontSize="sm" fontWeight="bold"> + Material File + </FormLabel> + <Input + fontSize="sm" + border="none" + type="file" + accept=".pdf, video/*" + size="lg" + onChange={handleFileChange} + /> + </FormControl> + </ModalBody> + + <ModalFooter justifyContent={"center"}> + <ButtonGroup> + <Button colorScheme="gray" flex="1" onClick={handleClose}> + Cancel + </Button> + <Button colorScheme="purple" flex="1" ml={3} + onClick={handleEditMaterial} + isDisabled={ + !( + isAllValid.title || + isAllValid.description || + isAllValid.file + ) + } + > + Edit + </Button> + </ButtonGroup> + </ModalFooter> + </ModalContent> + </Modal> + </> ); } -{/* Modal Add Material*/} -interface AddMaterialModalProps { +{ /* Modal Delete */ } +interface DeleteMaterialModalProps { isOpen: boolean; onClose: () => void; - handleAddMaterial: () => void; + successDelete: () => void; + materialId: number; } -export function AddMaterialModal({ +export function DeleteMaterialModal({ isOpen, onClose, - handleAddMaterial, -}: AddMaterialModalProps) { + successDelete, + materialId, +}: DeleteMaterialModalProps) { + const [isLoading, setIsLoading] = useState(false); + const [oldFile, setOldFile] = useState(""); + const newAxiosInstance = axios.create(axiosConfig()); + + useEffect(() => { // Fetch Data to Get Material Detail + const fetchData = async () => { + try { + setIsLoading(true); + const res = await newAxiosInstance.get(`${config.REST_API_URL}/material/${materialId}`); + if (res.data.status === 200) { + setOldFile(res.data.data.material_path); + } else { } + setIsLoading(false); + } catch (error) { + console.error('Error fetching material data:', error); + } + }; + fetchData(); + }, [materialId]); + + const handleDeleteMaterial = async () => { + try { + setIsLoading(true); + // Make a delete request to remove the old file + newAxiosInstance.delete(`${config.REST_API_URL}/material/deleteFile/${oldFile}`) + .then(() => { + console.log('Old file deleted successfully'); + }) + .catch((error) => { + console.error('Error deleting old file:', error); + }); + + const response = await newAxiosInstance.delete(`${config.REST_API_URL}/material/${materialId}`); + + console.log('Material Deleted successfully:', response.data.message); + + setIsLoading(false); + successDelete(); // Refresh new data without reloading page + } catch (error) { + console.error('Error deleting material:', error); + } + // window.location.reload(); // refresh to see new material added (should change to not reloading) + }; return ( - <Modal isOpen={isOpen} onClose={onClose}> - <ModalOverlay /> - <ModalContent> - <ModalHeader bg="#d78dff" textAlign={"center"}> - Add New Material - </ModalHeader> - <ModalCloseButton /> - <ModalBody> - <FormControl> - <FormLabel ms="4px" fontSize="sm" fontWeight="bold"> - Material Title - </FormLabel> - <Input - isRequired - variant="outline" - bg="white" - borderRadius="15px" - mb="5" - fontSize="sm" - size="lg" - placeholder={"Insert Title Here"} - /> - - <FormLabel ms="4px" fontSize="sm" fontWeight="bold"> - Material Description - </FormLabel> - <Textarea - isRequired - h="50" - maxHeight={"150"} - bg="white" - borderRadius="15px" - mb="5" - fontSize="sm" - size="lg" - placeholder={"Insert Description Here"} - /> - - <FormLabel ms="4px" fontSize="sm" fontWeight="bold"> - File - </FormLabel> - <Input - isRequired - fontSize="sm" - border="none" - type="file" - accept="image/*" - size="lg" - /> - </FormControl> - </ModalBody> - - <ModalFooter justifyContent={"center"}> - <ButtonGroup> - <Button colorScheme="gray" flex="1" onClick={onClose}> - Cancel - </Button> - <Button colorScheme="purple" flex="1" ml={3} onClick={handleAddMaterial}> - Add - </Button> - </ButtonGroup> - </ModalFooter> - </ModalContent> - </Modal> + <> + <Loading loading={isLoading} /> + <Modal isOpen={isOpen} onClose={onClose}> + <ModalOverlay /> + <ModalContent> + <ModalHeader textAlign={"center"}>Delete Material</ModalHeader> + <ModalCloseButton /> + <ModalBody textAlign={"center"}> + <Box + display="flex" + flexDirection="column" + alignItems="center" + justifyContent="center" + > + <Text as={BiError} fontSize={"150px"} color="red" /> + <Text>Are you sure want to delete this material?</Text> + </Box> + </ModalBody> + + <ModalFooter justifyContent={"center"}> + <ButtonGroup> + <Button colorScheme="gray" flex="1" onClick={onClose}> + Cancel + </Button> + <Button colorScheme="red" flex="1" ml={3} + onClick={handleDeleteMaterial} + > + Delete + </Button> + </ButtonGroup> + </ModalFooter> + </ModalContent> + </Modal> + </> ); -} \ No newline at end of file +} diff --git a/src/components/modals/module.tsx b/src/components/modals/module.tsx index 139448cefbe7533547afc9ca0ca1940eadc7bb70..7cb4e9162c7a53d1bf20d0dadd8ab0a8176f35c1 100644 --- a/src/components/modals/module.tsx +++ b/src/components/modals/module.tsx @@ -60,19 +60,25 @@ export function AddModuleModal({ setDescription(''); setIsLoading(false); successAdd(); // Refresh new data without reloading page - setIsAllValid({ ...isAllValid, title: false }); - setIsAllValid({ ...isAllValid, description: false }); } catch (error) { console.error('Error adding module:', error); } // window.location.reload(); // refresh to see new module added (should change to not reloading) + setIsAllValid(prevState => ({ + ...prevState, + title: false, + description: false, + })); }; const handleClose = () => { setTitle(""); setDescription(""); - setIsAllValid({ ...isAllValid, title: false }); - setIsAllValid({ ...isAllValid, description: false }); + setIsAllValid(prevState => ({ + ...prevState, + title: false, + description: false, + })); onClose(); }; @@ -226,42 +232,59 @@ export function EditModuleModal({ }); console.log('Module edited successfully:', response.data.message); - setIsLoading(false); successEdit(); // Refresh new data without reloading page - setIsAllValid({ ...isAllValid, title: false }); - setIsAllValid({ ...isAllValid, description: false }); } catch (error) { console.error('Error editing module:', error); } // window.location.reload(); // refresh to see new module added (should change to not reloading) + setIsAllValid(prevState => ({ + ...prevState, + title: false, + description: false, + })); }; const handleClose = () => { setTitle(editedTitle); setDescription(editedDescription); - setIsAllValid({ ...isAllValid, title: false }); - setIsAllValid({ ...isAllValid, description: false }); + setIsAllValid(prevState => ({ + ...prevState, + title: false, + description: false, + })); onClose(); }; const handleTitleChange = (e: React.ChangeEvent<HTMLInputElement>) => { if (e.target.value.length > 0) { setTitle(e.target.value); - setIsAllValid({ ...isAllValid, title: true }); + setIsAllValid(prevState => ({ + ...prevState, + title: true, + })); } else { setTitle(editedTitle); - setIsAllValid({ ...isAllValid, title: false }); + setIsAllValid(prevState => ({ + ...prevState, + title: false, + })); } }; const handleDescriptionChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => { if (e.target.value.length > 0) { setDescription(e.target.value); - setIsAllValid({ ...isAllValid, description: true }); + setIsAllValid(prevState => ({ + ...prevState, + description: true, + })); } else { setDescription(editedDescription); - setIsAllValid({ ...isAllValid, description: false }); + setIsAllValid(prevState => ({ + ...prevState, + description: false, + })); } }; @@ -320,9 +343,9 @@ export function EditModuleModal({ <Button colorScheme="purple" flex="1" ml={3} onClick={handleEditModule} isDisabled={ - !( - isAllValid.title || - isAllValid.description + !(( + (isAllValid.title && isAllValid.description) || + (isAllValid.title || isAllValid.description)) ) } > @@ -393,7 +416,7 @@ export function DeleteModuleModal({ Cancel </Button> <Button colorScheme="red" flex="1" ml={3} - onClick={handleDeleteModule} + onClick={handleDeleteModule} > Delete </Button> diff --git a/src/pages/Materials.tsx b/src/pages/Materials.tsx index 2329c08a0db100598cbb96c6d57dc49e1977f1fa..86d1e123f25c5ad7f05a120274e89e353f72146c 100644 --- a/src/pages/Materials.tsx +++ b/src/pages/Materials.tsx @@ -28,11 +28,13 @@ import { import { useParams } from "react-router-dom"; import { Modules, Materials } from "../types" import { EditModuleModal, AddModuleModal, DeleteModuleModal } from "../components/modals/module"; -// import { } from "../components/modals/material"; +import { EditMaterialModal, AddMaterialModal, DeleteMaterialModal } from "../components/modals/material"; import { axiosConfig } from "../utils/axios"; import config from "../config/config"; import axios from "axios"; import ReactPlayer from "react-player"; +import { Document, Page } from 'react-pdf' +import 'pdfjs-dist/build/pdf.worker.entry'; import PdfViewer from "../components/pdfviewer/pdfviewer"; import Loading from "../components/loading/Loading"; @@ -88,6 +90,10 @@ const ModuleMaterials = () => { }, [refreshModule]); const handleClickModule = (id: number) => { + setIdSelectedModules((prevId) => { + // console.log(prevId); // This will log the previous state + return id; + }); getMaterials(id); } @@ -124,7 +130,7 @@ const ModuleMaterials = () => { } // HANDLING DELETE MODULE - const [isModalDeleteOpen, setIsModalDeleteModuleOpen] = useState(false); + const [isModalDeleteModuleOpen, setIsModalDeleteModuleOpen] = useState(false); const handleOpenDeleteModule = (id: number) => { setIdSelectedModules(id); openModalDeleteModule(); @@ -145,16 +151,23 @@ const ModuleMaterials = () => { const initialMaterials: Materials[] = []; const [materials, setMaterials] = useState(initialMaterials); + const [refreshMaterial, setRefreshMaterial] = useState(false); + const [idSelectedMaterials, setIdSelectedMaterials] = useState(0); + + // FETCH DATA FROM SERVER const getMaterials = async (module_id: number) => { try { setIsLoading(true); - const res = await newAxiosInstance.get(`${config.REST_API_URL}/modul/course/${module_id}`); - const MaterialsData: Materials[] = res.data.data.map((module: any) => { + const res = await newAxiosInstance.get(`${config.REST_API_URL}/material/module/${module_id}`); + // console.log(res); + const MaterialsData: Materials[] = res.data.data.map((material: any) => { return { - id: module.id, - title: module.title, - description: module.description, - module_id: module.module_id, + id: material.id, + title: material.title, + description: material.description, + source_type: material.source_type, + material_path: material.material_path, + module_id: material.modul_id, }; }); setMaterials(MaterialsData); @@ -165,6 +178,53 @@ const ModuleMaterials = () => { } } + // HANDLING ADD MATERIAL + const [isModalAddMaterialOpen, setIsModalAddMaterialOpen] = useState(false); + const openModalAddMaterial = () => { + setIsModalAddMaterialOpen(true); + }; + const closeModalAddMaterial = () => { + setIsModalAddMaterialOpen(false); + }; + const successAddMaterial = () => { + setIsModalAddMaterialOpen(false); + getMaterials(idSelectedModules); + } + + // HANDLING EDIT MATERIAL + const [isModalEditMaterialOpen, setIsModalEditMaterialOpen] = useState(false); + const handleOpenEditMaterial = (id: number) => { + setIdSelectedMaterials(id); + openModalEditMaterial(); + } + const openModalEditMaterial = () => { + setIsModalEditMaterialOpen(true); + }; + const closeModalEditMaterial = () => { + setIsModalEditMaterialOpen(false); + }; + const successEditMaterial = () => { + setIsModalEditMaterialOpen(false); + getMaterials(idSelectedModules); + } + + // HANDLING DELETE MATERIAL + const [isModalDeleteMaterialOpen, setIsModalDeleteMaterialOpen] = useState(false); + const handleOpenDeleteMaterial = (id: number) => { + setIdSelectedMaterials(id); + openModalDeleteMaterial(); + } + const openModalDeleteMaterial = () => { + setIsModalDeleteMaterialOpen(true); + }; + const closeModalDeleteMaterial = () => { + setIsModalDeleteMaterialOpen(false); + }; + const successDeleteMaterial = () => { + setIsModalDeleteMaterialOpen(false); + getMaterials(idSelectedModules); + } + return ( <Container overflow="auto" maxW={"100vw"} maxH={"100vh"}> <Loading loading={isLoading} /> @@ -181,10 +241,9 @@ const ModuleMaterials = () => { onClose={closeModalEditModule} successEdit={successEditModule} moduleId={idSelectedModules} - /> - + /> <DeleteModuleModal - isOpen={isModalDeleteOpen} + isOpen={isModalDeleteModuleOpen} onClose={closeModalDeleteModule} successDelete={successDeleteModule} moduleId={idSelectedModules} @@ -192,12 +251,24 @@ const ModuleMaterials = () => { {/* --------------- MATERIAL POPUPS -------------------- */} - {/* <AddMaterialModal - isOpen={isModalAddOpen} - onClose={closeModalAdd} - handleAdd={handleAdd} - /> */} - + <AddMaterialModal + isOpen={isModalAddMaterialOpen} + onClose={closeModalAddMaterial} + successAdd={successAddMaterial} + moduleId={idSelectedModules} + /> + <EditMaterialModal + isOpen={isModalEditMaterialOpen} + onClose={closeModalEditMaterial} + successEdit={successEditMaterial} + materialId={idSelectedMaterials} + /> + <DeleteMaterialModal + isOpen={isModalDeleteMaterialOpen} + onClose={closeModalDeleteMaterial} + successDelete={successDeleteMaterial} + materialId={idSelectedMaterials} + /> <HStack align="start" justify="center"> <VStack maxW="20%" maxH="95vh" mt="1rem"> @@ -285,87 +356,137 @@ const ModuleMaterials = () => { ></Icon> </VStack> <VStack w="80%" h="95vh" mt="1rem" bg="white" > - {materials.length > 0 ? ( - <Box w="100%" h="94%" overflow={"hidden"}> - <Box w="full" p="3" px="8"> - <Text align="left" fontWeight={"bold"}> - Materials - </Text> - <Divider mt="1" borderColor="black.500" borderWidth="1" /> - </Box> - <Box + {idSelectedModules != 0 ? ( + <> + {materials.length > 0 ? ( + <Box w="100%" h="94%" overflow={"hidden"}> + <Box w="full" p="3" px="8"> + <Text align="left" fontWeight={"bold"}> + Materials + </Text> + <Divider mt="1" borderColor="black.500" borderWidth="1" /> + </Box> + <Box + px="10" + w="100%" + h="95%" + overflow="auto" + css={{ + "::-webkit-scrollbar": { + width: "10px", + }, + "::-webkit-scrollbar-thumb": { + background: "rgb(206, 207, 211)", + }, + "::-webkit-scrollbar-track": { + background: "rgba(255, 255, 255, 0.8)", + }, + }}> + {materials + .sort((a, b) => a.id - b.id) + .map((item) => ( + <Accordion key={item.id} allowToggle> + <AccordionItem> + <AccordionButton bg="#f0f0f0" borderRadius={"5"}> + <Box flex="1" textAlign="left"> + {item.title} + </Box> + <AccordionIcon /> + <Icon + as={BiSolidEdit} + fontSize={"18"} + color={"#564c95"} + _hover={{ color: "green" }} + cursor={"pointer"} + onClick={(e) => { + e.stopPropagation(); // Stop event propagation + handleOpenEditMaterial(item.id); + }} + ></Icon> + <Icon + as={BiSolidTrash} + fontSize={"18"} + color={"#564c95"} + _hover={{ color: "red" }} + cursor={"pointer"} + onClick={(e) => { + e.stopPropagation(); // Stop event propagation + handleOpenDeleteMaterial(item.id); + }} + ></Icon> + </AccordionButton> + {item.source_type === "PDF" ? ( + <AccordionPanel> + <Text align="left" fontSize={"md"} fontWeight={"bold"}>Deskripsi Materi:</Text> + <Text mb="5" align="left" fontSize={"sm"}>{item.description}</Text> + <div> + <iframe + src={`http://localhost:8000/file/${item.material_path}`} + width="100%" + height="500px" /> + </div> + </AccordionPanel> + ) : ( + <AccordionPanel> + <Text align="left" fontSize={"md"} fontWeight={"bold"}>Deskripsi Materi:</Text> + <Text mb="5" align="left" fontSize={"sm"}>{item.description}</Text> + <div> + <ReactPlayer + url={`http://localhost:8000/file/${item.material_path}`} + width="100%" + height="500px" + controls + /> + </div> + </AccordionPanel> + )} + </AccordionItem> + <Divider mt="3" borderColor="transparent" /> + </Accordion> + ))} + </Box> + </Box> + ) : (<Box px="5" w="100%" - h="95%" - overflow="auto" - css={{ - "::-webkit-scrollbar": { - width: "3px", - }, - "::-webkit-scrollbar-thumb": { - background: "rgb(206, 207, 211)", - }, - "::-webkit-scrollbar-track": { - background: "rgba(255, 255, 255, 0.8)", - }, - }}> - {materials - .sort((a, b) => a.id - b.id) - .map((item) => ( - <Accordion allowToggle> - <AccordionItem> - <AccordionButton bg="#f0f0f0" borderRadius={"5"}> - <Box flex="1" textAlign="left"> - {item.title} - </Box> - <AccordionIcon /> - <Icon - as={BiSolidEdit} - fontSize={"18"} - color={"#564c95"} - _hover={{ color: "green" }} - cursor={"pointer"} - // onClick={() => openModalEditModule(item.id, item.title, item.description)} - ></Icon> - <Icon - as={BiSolidTrash} - fontSize={"18"} - color={"#564c95"} - _hover={{ color: "red" }} - cursor={"pointer"} - // onClick={() => openModalDelete(item.id)} - ></Icon> - </AccordionButton> - <AccordionPanel> - <Text align="left" fontSize={"sm"}>{item.description}</Text> - <PdfViewer pdfPath={"/Quiz-1.pdf"} /> - </AccordionPanel> - </AccordionItem> - <Divider mt="3" borderColor="transparent" /> - </Accordion> - ))} + h="94%"> + <Box w="full" p="3"> + <Text align="left" fontWeight={"bold"}> + No Material Available for This Module + </Text> + <Divider mt="1" borderColor="black.500" borderWidth="1" /> + </Box> + </Box> + ) + } + < Icon + as={BiPlusCircle} + fontSize={"26"} + color={"#564c95"} + _hover={{ color: "green" }} + cursor={"pointer"} + onClick={() => openModalAddMaterial()} + ></Icon> + </> + ) : ( + <Box + px="5" + w="100%" + h="94%" + display="flex" + alignItems="center" + justifyContent="center" + > + <Box w="full" p="3"> + <Text align="center" fontWeight={"bold"} fontSize={"30"}> + Welcome To This Course! + </Text> + <Text align="center" fontSize={"24"}> + Please Select a Module to See the Materials + </Text> </Box> </Box> - ) : (<Box - px="5" - w="100%" - h="94%"> - <Box w="full" p="3"> - <Text align="left" fontWeight={"bold"}> - No Material Available for This Module - </Text> - <Divider mt="1" borderColor="black.500" borderWidth="1" /> - </Box> - </Box> )} - <Icon - as={BiPlusCircle} - fontSize={"26"} - color={"#564c95"} - _hover={{ color: "green" }} - cursor={"pointer"} - // onClick={() => openModalAdd(item.module_id, item.title)} - ></Icon> </VStack> </HStack> </Container >