DEV Community

Navnit Rai
Navnit Rai

Posted on

AdminCourses

import {
  Box,
  Button,
  Grid,
  Heading,
  HStack,
  Image,
  Table,
  TableCaption,
  TableContainer,
  Tbody,
  Td,
  Th,
  Thead,
  Tr,
  useDisclosure,
} from '@chakra-ui/react'; // Importing Chakra UI components for styling.
import React, { useState, useEffect } from 'react'; // Importing React, useState, and useEffect for state and lifecycle management.
import { RiDeleteBin7Fill } from 'react-icons/ri'; // Importing delete icon from react-icons.
import { useDispatch, useSelector } from 'react-redux'; // Importing hooks for interacting with Redux state.
import cursor from '../../../assets/images/cursor.png'; // Custom cursor image.
import Sidebar from '../Sidebar'; // Importing Sidebar component.
import CourseModal from './CourseModal'; // Importing CourseModal component for viewing and adding lectures.
import {
  getAllCourses,
  getCourseLectures,
} from '../../../redux/actions/course'; // Redux actions for getting courses and lectures.
import {
  addLecture,
  deleteCourse,
  deleteLecture,
} from '../../../redux/actions/admin'; // Redux actions for adding/deleting courses/lectures.
import toast from 'react-hot-toast'; // For displaying toast notifications.

const AdminCourses = () => {
  // Using Redux selectors to get the state from the Redux store.
  const { courses, lectures } = useSelector(state => state.course); 
  const { loading, error, message } = useSelector(state => state.admin);

  const dispatch = useDispatch(); // useDispatch hook for dispatching actions.
  const { isOpen, onClose, onOpen } = useDisclosure(); // useDisclosure for handling modal open/close state.

  // Local state for managing selected courseId and courseTitle.
  const [courseId, setCourseId] = useState('');
  const [courseTitle, setCourseTitle] = useState('');

  // Function to handle fetching course lectures and opening the modal.
  const coureDetailsHandler = (courseId, title) => {
    dispatch(getCourseLectures(courseId)); // Dispatches action to fetch course lectures.
    onOpen(); // Opens the modal.
    setCourseId(courseId); // Sets the selected course ID.
    setCourseTitle(title); // Sets the selected course title.
  };

  // Function to handle deleting a course by courseId.
  const deleteButtonHandler = courseId => {
    console.log(courseId); // Logs courseId for debugging.
    dispatch(deleteCourse(courseId)); // Dispatches action to delete the course.
  };

  // Function to handle deleting a specific lecture within a course.
  const deleteLectureButtonHandler = async (courseId, lectureId) => {
    await dispatch(deleteLecture(courseId, lectureId)); // Deletes the lecture.
    dispatch(getCourseLectures(courseId)); // Fetches updated lectures for the course.
  };

  // Function to handle adding a new lecture to a course.
  const addLectureHandler = async (e, courseId, title, description, video) => {
    e.preventDefault(); // Prevents default form submission behavior.
    const myForm = new FormData(); // Creating a FormData object to send file data.

    // Appending form data for the lecture.
    myForm.append('title', title);
    myForm.append('description', description);
    myForm.append('file', video);

    await dispatch(addLecture(courseId, myForm)); // Dispatches action to add the lecture.
    dispatch(getCourseLectures(courseId)); // Fetches updated lectures for the course.
  };

  // useEffect hook to handle side effects such as error handling and fetching data on component load.
  useEffect(() => {
    if (error) {
      toast.error(error); // Displays an error toast.
      dispatch({ type: 'clearError' }); // Clears the error state in Redux.
    }

    if (message) {
      toast.success(message); // Displays a success toast.
      dispatch({ type: 'clearMessage' }); // Clears the message state in Redux.
    }

    dispatch(getAllCourses()); // Dispatches action to get all courses on component mount.
  }, [dispatch, error, message, onClose]);

  return (
    <Grid
      css={{
        cursor: `url(${cursor}), default`, // Custom cursor for the page.
      }}
      minH={'100vh'} // Minimum height of 100vh (full viewport height).
      templateColumns={['1fr', '5fr 1fr']} // Grid layout: full width on small screens, 5:1 ratio on larger screens.
    >
      <Box p={['0', '8']} overflowX="auto"> {/* Box for main content with responsive padding */}
        <Heading
          textTransform={'uppercase'} // Uppercase text for heading.
          children="All Courses" // Page heading.
          my="16" // Margin for vertical spacing.
          textAlign={['center', 'left']} // Responsive text alignment (center on small screens, left on large).
        />

        {/* Table containing all the courses */}
        <TableContainer w={['100vw', 'full']}>
          <Table variant={'simple'} size="lg">
            <TableCaption>All available courses in the database</TableCaption> {/* Table caption */}

            {/* Table headers */}
            <Thead>
              <Tr>
                <Th>Id</Th>
                <Th>Poster</Th>
                <Th>Title</Th>
                <Th>Category</Th>
                <Th>Creator</Th>
                <Th isNumeric>Views</Th>
                <Th isNumeric>Lectures</Th>
                <Th isNumeric>Action</Th>
              </Tr>
            </Thead>

            {/* Table body with dynamic course rows */}
            <Tbody>
              {courses.map(item => (
                <Row
                  coureDetailsHandler={coureDetailsHandler} // Passes the course details handler.
                  deleteButtonHandler={deleteButtonHandler} // Passes the delete handler.
                  key={item._id} // Unique key for each row.
                  item={item} // The course data.
                  loading={loading} // Loading state.
                />
              ))}
            </Tbody>
          </Table>
        </TableContainer>

        {/* Course modal to manage lectures for the selected course */}
        <CourseModal
          isOpen={isOpen}
          onClose={onClose}
          id={courseId}
          courseTitle={courseTitle}
          deleteButtonHandler={deleteLectureButtonHandler}
          addLectureHandler={addLectureHandler}
          lectures={lectures}
          loading={loading}
        />
      </Box>

      {/* Sidebar for navigation (on the right side of the screen) */}
      <Sidebar />
    </Grid>
  );
};

// Row component to render each row in the courses table.
function Row({ item, coureDetailsHandler, deleteButtonHandler, loading }) {
  return (
    <Tr>
      <Td>#{item._id}</Td> {/* Course ID */}

      <Td>
        <Image src={item.poster.url} /> {/* Course poster image */}
      </Td>

      <Td>{item.title}</Td> {/* Course title */}
      <Td textTransform={'uppercase'}>{item.category}</Td> {/* Course category */}
      <Td>{item.createdBy}</Td> {/* Course creator */}
      <Td isNumeric>{item.views}</Td> {/* Number of views (numeric) */}
      <Td isNumeric>{item.numOfVideos}</Td> {/* Number of lectures (numeric) */}

      {/* Action buttons to view lectures or delete the course */}
      <Td isNumeric>
        <HStack justifyContent={'flex-end'}>
          <Button
            onClick={() => coureDetailsHandler(item._id, item.title)} // View lectures button.
            variant={'outline'}
            color="purple.500"
            isLoading={loading}
          >
            View Lectures
          </Button>

          <Button
            onClick={() => deleteButtonHandler(item._id)} // Delete course button.
            color={'purple.600'}
            isLoading={loading}
          >
            <RiDeleteBin7Fill /> {/* Delete icon */}
          </Button>
        </HStack>
      </Td>
    </Tr>
  );
}

export default AdminCourses; // Exporting the AdminCourses component.

Enter fullscreen mode Exit fullscreen mode

Top comments (0)