Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

E2461: UI for Courses #70

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions src/components/Form/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface IFormProps {
tooltipPlacement?: "top" | "right" | "bottom" | "left";
inputGroupPrepend?: ReactNode;
inputGroupAppend?: ReactNode;

}

export interface IFormOption {
Expand All @@ -25,6 +26,7 @@ export interface IFormOption {

export interface IFormPropsWithOption extends IFormProps {
options: IFormOption[];
onChange?: (event: React.ChangeEvent<HTMLSelectElement>) => void;
}

export interface IFormikFieldProps {
Expand Down
93 changes: 70 additions & 23 deletions src/pages/Courses/CourseEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import FormInput from "components/Form/FormInput";
import FormSelect from "components/Form/FormSelect";
import { Form, Formik, FormikHelpers } from "formik";
import useAPI from "hooks/useAPI";
import React, { useEffect } from "react";
import React, { useEffect, useState } from "react";
import { Button, InputGroup, Modal } from "react-bootstrap";
import { useDispatch, useSelector } from "react-redux";
import { useLoaderData, useLocation, useNavigate } from "react-router-dom";
Expand All @@ -15,16 +15,17 @@ import { IEditor, ROLE } from "../../utils/interfaces";
import { ICourseFormValues, courseVisibility, noSpacesSpecialCharsQuotes, transformCourseRequest } from "./CourseUtil";

/**
* @author Atharva Thorve, on December, 2023
* @author Mrityunjay Joshi, on December, 2023
* @author Suraj Raghu Kumar, on Oct, 2024
* @author Yuktasree Muppala on Oct, 2024
* @author Harvardhan Patil on Oct, 2024
*/

// CourseEditor Component: Modal for creating or updating a course.
const initialValues: ICourseFormValues = {
name: "",
directory: "",
private: [],
institution_id: -1,
institution_id: 0,
instructor_id: -1,
info: "",
};
Expand All @@ -44,37 +45,80 @@ const validationSchema = Yup.object({
});

const CourseEditor: React.FC<IEditor> = ({ mode }) => {

// API hook for making requests
const { data: courseResponse, error: courseError, sendRequest } = useAPI();
const { data: users, sendRequest: fetchusers } = useAPI();
const auth = useSelector(
(state: RootState) => state.authentication,
(prev, next) => prev.isAuthenticated === next.isAuthenticated
);
const { courseData, institutions, instructors }: any = useLoaderData();
const { courseData, institutions }: any = useLoaderData();
const dispatch = useDispatch();
const navigate = useNavigate();
const location = useLocation();

initialValues.institution_id = auth.user.institution_id;
interface IFormOption {
label: string;
value: string;
}

const [filteredInstructors, setFilteredInstructors] = useState<IFormOption[]>([]);
const [selectedInstitutionId, setSelectedInstitutionId] = useState<number | null>(null); // New state for selected institution

// Close the modal if the course is updated successfully and navigate to the courses page
useEffect(() => {
if (courseResponse && courseResponse.status >= 200 && courseResponse.status < 300) {
dispatch(
alertActions.showAlert({
variant: "success",
message: `Course ${courseData.name} ${mode}d successfully!`,
})
);
navigate(location.state?.from ? location.state.from : "/courses");
}
}, [dispatch, mode, navigate, courseData.name, courseResponse, location.state?.from]);
fetchusers({url:'/users'});
}, [fetchusers]);

// Show the error message if the course is not updated successfully
// Filter instructors based on selected institution
useEffect(() => {
courseError && dispatch(alertActions.showAlert({ variant: "danger", message: courseError }));
}, [courseError, dispatch]);

if (users) {
const instructorsList: IFormOption[] = [{ label: 'Select an Instructor', value: '' }];
console.log('Selected Institution ID:', selectedInstitutionId)

// Filter by instructors by institution
const onlyInstructors = users.data.filter((user: any) =>
(user.role.name === 'Instructor')&& (user.institution.id === selectedInstitutionId));
console.log('Users:', users.data)
onlyInstructors.forEach((instructor: any) => {
instructorsList.push({ label: instructor.name, value: String(instructor.id) });
});
setFilteredInstructors(instructorsList);

}
}, [users, selectedInstitutionId]); // Re-run this effect when users or selectedInstitutionId changes

// Handle institution selection change and implement Single Responsibility Principle
const handleInstitutionChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
const institutionId = Number(event.target.value);
setSelectedInstitutionId(institutionId);
};
// Success handler for course submission
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In CourseEditor.tsx, the handleCourseSuccess and handleCourseError functions have been separated to enhance readability and follow the Single Responsibility Principle (SRP).

const handleCourseSuccess = () => {
if (courseResponse && courseResponse.status >= 200 && courseResponse.status < 300) {
dispatch(
alertActions.showAlert({
variant: "success",
message: `Course ${courseData.name} ${mode}d successfully!`,
})
);
navigate(location.state?.from ? location.state.from : "/courses");
}
};
// Error handler for course submission
const handleCourseError = () => {
if (courseError) {
dispatch(alertActions.showAlert({ variant: "danger", message: courseError }));
}
};
// useEffect to monitor success response
useEffect(() => {
handleCourseSuccess();
}, [courseResponse]);
// useEffect to monitor error response
useEffect(() => {
handleCourseError();
}, [courseError]);

// Function to handle form submission
const onSubmit = (values: ICourseFormValues, submitProps: FormikHelpers<ICourseFormValues>) => {
Expand Down Expand Up @@ -112,10 +156,11 @@ const CourseEditor: React.FC<IEditor> = ({ mode }) => {
initialValues={mode === "update" ? courseData : initialValues}
onSubmit={onSubmit}
validationSchema={validationSchema}
validateOnChange={false}
validateOnChange={true}
enableReinitialize={true}
>
{(formik) => {

return (
<Form>
<FormSelect
Expand All @@ -126,12 +171,14 @@ const CourseEditor: React.FC<IEditor> = ({ mode }) => {
inputGroupPrepend={
<InputGroup.Text id="course-inst-prep">Institution</InputGroup.Text>
}

onChange={handleInstitutionChange} // Add onChange to handle institution selection
/>
<FormSelect
controlId="course-instructor"
name="instructor_id"
disabled={mode === "update" || auth.user.role !== ROLE.SUPER_ADMIN.valueOf()}
options={instructors}
options={filteredInstructors}
inputGroupPrepend={
<InputGroup.Text id="course-inst-prep">Instructors</InputGroup.Text>
}
Expand Down