DEV Community

Navnit Rai
Navnit Rai

Posted on

CreateCourse.jsx

import {
  Button,
  Container,
  Grid,
  Heading,
  Image,
  Input,
  Select,
  VStack,
} from '@chakra-ui/react';
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import cursor from '../../../assets/images/cursor.png'; // Custom cursor image
import { createCourse } from '../../../redux/actions/admin'; // Redux action to create a course
import { fileUploadCss } from '../../Auth/Register'; // Custom file upload styles
import Sidebar from '../Sidebar'; // Sidebar component for admin dashboard
import toast from 'react-hot-toast'; // For toast notifications

const CreateCourse = () => {
  const [title, setTitle] = useState('');           // State for course title
  const [description, setDescription] = useState(''); // State for course description
  const [createdBy, setCreatedBy] = useState('');   // State for creator's name
  const [category, setCategory] = useState('');     // State for course category
  const [image, setImage] = useState('');           // State for the course image file
  const [imagePrev, setImagePrev] = useState('');   // State for the image preview

  const dispatch = useDispatch();                   // Dispatch function from Redux
  const { loading, error, message } = useSelector(state => state.admin); // Access Redux state

  // List of categories for the course
  const categories = [
    'Web development',
    'Artificial Intelligence',
    'Data Structure & Algorithm',
    'App Development',
    'Data Science',
    'Game Development',
  ];

  // Handle file input change for the course image
  const changeImageHandler = e => {
    const file = e.target.files[0];          // Get the selected file
    const reader = new FileReader();         // Create a FileReader to preview the image

    reader.readAsDataURL(file);              // Read the file as a data URL

    reader.onloadend = () => {
      setImagePrev(reader.result);           // Set the preview image
      setImage(file);                        // Set the file to be uploaded
    };
  };

  // Handle form submission for creating a new course
  const submitHandler = e => {
    e.preventDefault();                      // Prevent the default form submission
    const myForm = new FormData();           // Create a FormData object for sending form data
    myForm.append('title', title);           // Add title to the form data
    myForm.append('description', description); // Add description to the form data
    myForm.append('category', category);     // Add category to the form data
    myForm.append('createdBy', createdBy);   // Add creator's name to the form data
    myForm.append('file', image);            // Add the image file to the form data
    dispatch(createCourse(myForm));          // Dispatch the createCourse action
  };

  // useEffect hook to handle errors and success messages from Redux
  useEffect(() => {
    if (error) {
      toast.error(error);                    // Show error toast notification
      dispatch({ type: 'clearError' });      // Clear the error in Redux
    }

    if (message) {
      toast.success(message);                // Show success toast notification
      dispatch({ type: 'clearMessage' });    // Clear the success message in Redux
    }
  }, [dispatch, error, message]);            // Dependency array: triggers when dispatch, error, or message changes

  return (
    <Grid
      css={{
        cursor: `url(${cursor}), default`,   // Set a custom cursor
      }}
      minH={'100vh'}                         // Full height grid
      templateColumns={['1fr', '5fr 1fr']}   // Responsive grid: full-width on small screens, 5:1 ratio on large screens
    >
      <Container py="16">
        <form onSubmit={submitHandler}>
          <Heading
            textTransform={'uppercase'}      // Uppercase text for heading
            children="Create Course"         // Heading text
            my="16"                          // Margin for heading
            textAlign={['center', 'left']}   // Centered text on small screens, left-aligned on larger screens
          />

          <VStack m="auto" spacing={'8'}>    {/* Vertical stack for form elements */}
            {/* Title input */}
            <Input
              value={title}
              onChange={e => setTitle(e.target.value)}
              placeholder="Title"
              type={'text'}
              focusBorderColor="purple.300"   // Purple border on focus
            />{' '}
            {/* Description input */}
            <Input
              value={description}
              onChange={e => setDescription(e.target.value)}
              placeholder="Description"
              type={'text'}
              focusBorderColor="purple.300"
            />
            {/* Creator name input */}
            <Input
              value={createdBy}
              onChange={e => setCreatedBy(e.target.value)}
              placeholder="Creator Name"
              type={'text'}
              focusBorderColor="purple.300"
            />
            {/* Category select input */}
            <Select
              focusBorderColor="purple.300"
              value={category}
              onChange={e => setCategory(e.target.value)}
            >
              <option value="">Category</option> {/* Default option */}
              {categories.map(item => (
                <option key={item} value={item}> {/* Options for categories */}
                  {item}
                </option>
              ))}
            </Select>
            {/* Image file input */}
            <Input
              accept="image/*"                // Accept image files only
              required
              type={'file'}
              focusBorderColor="purple.300"
              css={{
                '&::file-selector-button': {  // Custom CSS for file input
                  ...fileUploadCss,
                  color: 'purple',
                },
              }}
              onChange={changeImageHandler}   // Handle file input change
            />
            {/* Display image preview if image is selected */}
            {imagePrev && (
              <Image src={imagePrev} boxSize="64" objectFit={'contain'} />
            )}
            {/* Submit button */}
            <Button
              isLoading={loading}             // Show loading spinner when submitting
              w="full"
              colorScheme={'purple'}          // Purple button style
              type="submit"                   // Submit button
            >
              Create
            </Button>
          </VStack>
        </form>
      </Container>

      <Sidebar />                             {/* Sidebar component */}
    </Grid>
  );
};

export default CreateCourse;                  // Export CreateCourse component

Enter fullscreen mode Exit fullscreen mode

Top comments (0)