DEV Community

Navnit Rai
Navnit Rai

Posted on

components/Courses /Courses.jsx

import {
  Button,
  Container,
  Heading,
  HStack,
  Image,
  Input,
  Stack,
  Text,
  VStack,
} from '@chakra-ui/react'; // Importing Chakra UI components for styling
import React, { useEffect, useState } from 'react'; // Importing React and hooks
import { Link } from 'react-router-dom'; // For routing
import { useDispatch, useSelector } from 'react-redux'; // For accessing Redux state and dispatch
import { getAllCourses } from '../../redux/actions/course'; // Action to fetch courses
import toast from 'react-hot-toast'; // For notifications
import { addToPlaylist } from '../../redux/actions/profile'; // Action to add course to playlist
import { loadUser } from '../../redux/actions/user'; // Action to load user data

// Component to display individual course details
const Course = ({
  views,
  title,
  imageSrc,
  id,
  addToPlaylistHandler,
  creator,
  description,
  lectureCount,
  loading,
}) => {
  return (
    <VStack className="course" alignItems={['center', 'flex-start']}>
      <Image src={imageSrc} boxSize="60" objectFit={'contain'} /> {/* Course image */}
      <Heading
        textAlign={['center', 'left']}
        maxW="200px"
        size={'sm'}
        fontFamily={'sans-serif'}
        noOfLines={3
        } // Title with line limit
        children={title}
      />
      <Text noOfLines={2} children={description} /> {/* Course description */}

      <HStack>
        <Text
          fontWeight={'bold'}
          textTransform="uppercase"
          children={'Creator'}
        />
        <Text
          fontFamily={'body'}
          textTransform="uppercase"
          children={creator} // Course creator's name
        />
      </HStack>

      <Heading
        textAlign={'center'}
        size="xs"
        children={`Lectures - ${lectureCount}`} // Number of lectures
        textTransform="uppercase"
      />

      <Heading
        size="xs"
        children={`Views - ${views}`} // Number of views
        textTransform="uppercase"
      />

      <Stack direction={['column', 'row']} alignItems="center">
        <Link to={`/course/${id}`}> {/* Link to the course details page */}
          <Button colorScheme={'yellow'}>Watch Now</Button>
        </Link>
        <Button
          isLoading={loading} // Loading state for button
          variant={'ghost'}
          colorScheme={'yellow'}
          onClick={() => addToPlaylistHandler(id)} // Add course to playlist
        >
          Add to playlist
        </Button>
      </Stack>
    </VStack>
  );
};

// Main component to display all courses
const Courses = () => {
  const [keyword, setKeyword] = useState(''); // State for search keyword
  const [category, setCategory] = useState(''); // State for selected category
  const dispatch = useDispatch(); // Accessing dispatch function

  // Handler for adding course to playlist
  const addToPlaylistHandler = async courseId => {
    await dispatch(addToPlaylist(courseId)); // Dispatch add to playlist action
    dispatch(loadUser()); // Reload user data
  };

  // Predefined categories for filtering courses
  const categories = [
    'Web development',
    'Artificial Intelligence',
    'Data Structure & Algorithm',
    'App Development',
    'Data Science',
    'Game Development',
  ];

  const { loading, courses, error, message } = useSelector(
    state => state.course // Accessing course-related state from Redux
  );

  // Effect to fetch courses based on keyword and category
  useEffect(() => {
    dispatch(getAllCourses(category, keyword)); // Fetch courses

    // Handle error messages
    if (error) {
      toast.error(error); // Show error notification
      dispatch({ type: 'clearError' }); // Clear error from state
    }

    // Handle success messages
    if (message) {
      toast.success(message); // Show success notification
      dispatch({ type: 'clearMessage' }); // Clear message from state
    }
  }, [category, keyword, dispatch, error, message]); // Dependencies for the effect

  return (
    <Container minH={'95vh'} maxW="container.lg" paddingY={'8'}>
      <Heading children="All Courses" m={'8'} /> {/* Main heading for the page */}

      <Input
        value={keyword} // Controlled input value for search
        onChange={e => setKeyword(e.target.value)} // Update keyword on change
        placeholder="Search a course..."
        type={'text'}
        focusBorderColor="yellow.500" // Border color on focus
      />

      <HStack
        overflowX={'auto'} // Allow horizontal scrolling for categories
        paddingY="8"
        css={{
          '&::-webkit-scrollbar': {
            display: 'none', // Hide scrollbar
          },
        }}
      >
        {categories.map((item, index) => (
          <Button key={index} onClick={() => setCategory(item)} minW={'60'}>
            <Text children={item} /> {/* Category button */}
          </Button>
        ))}
      </HStack>

      <Stack
        direction={['column', 'row']}
        flexWrap="wrap"
        justifyContent={['flex-start', 'space-evenly']} // Responsive layout for courses
        alignItems={['center', 'flex-start']}
      >
        {courses.length > 0 ? ( // Conditional rendering based on courses availability
          courses.map(item => (
            <Course
              key={item._id} // Unique key for each course
              title={item.title}
              description={item.description}
              views={item.views}
              imageSrc={item.poster.url}
              id={item._id}
              creator={item.createdBy}
              lectureCount={item.numOfVideos}
              addToPlaylistHandler={addToPlaylistHandler}
              loading={loading}
            />
          ))
        ) : (
          <Heading mt="4" children="Courses Not Found" /> // Message when no courses are found
        )}
      </Stack>
    </Container>
  );
};

export default Courses; // Exporting Courses component

Enter fullscreen mode Exit fullscreen mode

Top comments (0)