components/Courses /Courses.jsx
Navnit Rai
Posted on September 22, 2024
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
💖 💪 🙅 🚩
Navnit Rai
Posted on September 22, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
githubcopilot AI Innovations at Microsoft Ignite 2024 What You Need to Know (Part 2)
November 29, 2024