From c2d9cfed206060418998f46d61be3a8032dbad5d Mon Sep 17 00:00:00 2001 From: ashwaqaljanahi2021 Date: Tue, 5 Nov 2024 09:48:28 -0500 Subject: [PATCH] completed enrolled/not-enrolled feature --- .../components/listItems/courseListItem.scss | 18 ++- .../src/components/misc/globalToolbar.tsx | 2 +- .../listPages/courses/coursesListPage.tsx | 120 ++++++++++-------- package-lock.json | 34 +++++ package.json | 5 + 5 files changed, 121 insertions(+), 58 deletions(-) create mode 100644 package-lock.json create mode 100644 package.json diff --git a/devU-client/src/components/listItems/courseListItem.scss b/devU-client/src/components/listItems/courseListItem.scss index c5d73f6..e8449c5 100644 --- a/devU-client/src/components/listItems/courseListItem.scss +++ b/devU-client/src/components/listItems/courseListItem.scss @@ -60,13 +60,29 @@ color: $text-color; - + &.enrolled { + background-color: #dff0d8; // Light green background for enrolled courses + border-color: #3c763d; // Darker green border for enrolled courses + color: #3c763d; // Change text color to darker green + } &:hover, &:focus { background: $list-item-background-hover; } } +.enrollmentStatus { + margin-left: 10px; + font-weight: bold; // Make it bold for emphasis +} + +.enrolled { + color: green; // Change color for enrolled courses +} + +.notEnrolled { + color: red; // Change color for not enrolled courses +} @media (max-width: $medium) { .subText { diff --git a/devU-client/src/components/misc/globalToolbar.tsx b/devU-client/src/components/misc/globalToolbar.tsx index 7149e5e..29a894e 100644 --- a/devU-client/src/components/misc/globalToolbar.tsx +++ b/devU-client/src/components/misc/globalToolbar.tsx @@ -29,7 +29,7 @@ const GlobalToolbar = () => { { - My Courses + Join a Course } {/**/} diff --git a/devU-client/src/components/pages/listPages/courses/coursesListPage.tsx b/devU-client/src/components/pages/listPages/courses/coursesListPage.tsx index b1e0026..2184be9 100644 --- a/devU-client/src/components/pages/listPages/courses/coursesListPage.tsx +++ b/devU-client/src/components/pages/listPages/courses/coursesListPage.tsx @@ -1,70 +1,81 @@ -import React, {useEffect, useState} from 'react' -import {Course, UserCourse} from 'devu-shared-modules' -import LoadingOverlay from 'components/shared/loaders/loadingOverlay' -import PageWrapper from 'components/shared/layouts/pageWrapper' -import Dropdown, {Option} from 'components/shared/inputs/dropdown' -import ErrorPage from '../../errorPage/errorPage' -import RequestService from 'services/request.service' -import styles from './coursesListPage.scss' +import React, { useEffect, useState } from 'react'; +import { Course } from 'devu-shared-modules'; +import LoadingOverlay from 'components/shared/loaders/loadingOverlay'; +import PageWrapper from 'components/shared/layouts/pageWrapper'; +import Dropdown, { Option } from 'components/shared/inputs/dropdown'; +import ErrorPage from '../../errorPage/errorPage'; +import RequestService from 'services/request.service'; +import styles from './coursesListPage.scss'; import CourseListItem from "../../../listItems/courseListItem"; -// import {useAppSelector} from "../../../../redux/hooks"; import Button from "@mui/material/Button"; -import {useHistory} from "react-router-dom"; +import { useHistory } from "react-router-dom"; +import { useAppSelector } from "../../../../redux/hooks"; -type Filter = true | false +type Filter = true | false; const filterOptions: Option[] = [ - {label: 'Expand All', value: true}, - {label: 'Collapse All', value: false}, -] + { label: 'Expand All', value: true }, + { label: 'Collapse All', value: false }, +]; const UserCoursesListPage = () => { + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [allCourses, setAllCourses] = useState([]); + const [filter, setFilter] = useState(false); + const history = useHistory(); - const [loading, setLoading] = useState(true) - const [error, setError] = useState(null) - const [userCourses, setUserCourses] = useState(new Array()) - const [filter, setFilter] = useState(false ) - const history = useHistory() - - //Temporary place to store state for all courses - const [allCourses, setAllCourses] = useState(new Array()) + // Get userId from Redux store + const userId = useAppSelector((store) => store.user.id); useEffect(() => { - fetchData() - }, []) + fetchData(); + }, []); const fetchData = async () => { try { - // const userCourses = await RequestService.get(`/api/user-courses?filterBy=${filter}`) - const courseRequests = userCourses.map((u) => RequestService.get(`/api/courses/${u.courseId}`)) - const courses = await Promise.all(courseRequests) - - // Mapify course ids so we can look them up more easilly via their id - const courseMap: Record = {} - for (const course of courses) courseMap[course.id || ''] = course - - // Temporary place to grab and display all courses - const allCourses = await RequestService.get('/api/courses') - setAllCourses(allCourses) - - setUserCourses(userCourses) + // Fetch user-specific courses + const userCourseData = await RequestService.get<{ + instructorCourses: Course[]; + activeCourses: Course[]; + pastCourses: Course[]; + upcomingCourses: Course[]; + }>(`/api/courses/user/${userId}`); + + // Flatten and combine user course data into a single array + const userCoursesList = [ + ...userCourseData.instructorCourses, + ...userCourseData.activeCourses, + ...userCourseData.pastCourses, + ...userCourseData.upcomingCourses, + ]; + + // Fetch all courses + const allCourseData = await RequestService.get(`/api/courses`); + + // Filter to get courses the user is not enrolled in + const unenrolledCourses = allCourseData.filter( + (course) => !userCoursesList.some((userCourse) => userCourse.id === course.id) + ); + + + setAllCourses(unenrolledCourses); } catch (error: any) { - setError(error) + setError(error); } finally { - setLoading(false) + setLoading(false); } - } + }; const handleFilterChange = (updatedFilter: Filter) => { - setFilter(updatedFilter) - } + setFilter(updatedFilter); + }; - if (loading) return - if (error) return - - const defaultOption = filterOptions.find((o) => o.value === filter) + if (loading) return ; + if (error) return ; + const defaultOption = filterOptions.find((o) => o.value === filter); return ( @@ -73,9 +84,8 @@ const UserCoursesListPage = () => {

All Courses

-
{ />
- {allCourses.map(course => ( - + {allCourses.map((course) => ( + ))}
- ) - - -} + ); +}; -export default UserCoursesListPage +export default UserCoursesListPage; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..84cd429 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,34 @@ +{ + "name": "devU", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "@types/react": "^18.3.12" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.3.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", + "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..ab744a6 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "devDependencies": { + "@types/react": "^18.3.12" + } +}