diff --git a/backend/controllers/RatingAndReview.js b/backend/controllers/RatingAndReview.js
index fbf86b8..c9e44c8 100644
--- a/backend/controllers/RatingAndReview.js
+++ b/backend/controllers/RatingAndReview.js
@@ -5,10 +5,11 @@ const mongoose = require("mongoose");
// create Rating and review
exports.createRating = async (req, res) => {
+ console.log("----------------------------------------");
try {
// get data
const { rating, review, courseId } = req.body;
- const { userId } = req.user.id;
+ const userId = req.user.id;
// validate data
if (!rating || !review || !courseId || !userId) {
@@ -17,25 +18,15 @@ exports.createRating = async (req, res) => {
.json({ success: false, message: "Please enter all the fields" });
}
- // check if user is enrolled or not
- const user = await User.findById(userId);
- if (!user.courses.includes(courseId)) {
- return res.status(400).json({
- success: false,
- message: "You are not enrolled in this course",
- });
- }
-
- // TODO : not forget to run this method
- // const courseDetails = await Course.findOne({
- // _id: courseId,
- // studentsEnrolled: { $elemMatch: { $eq: userId } },
- // });
+ const courseDetails = await Course.findOne({
+ _id: courseId,
+ studentsEnrolled: { $elemMatch: { $eq: userId } },
+ }); //check if user is enrolled or not
if (!courseDetails) {
- return res.status(400).json({
+ return res.status(404).json({
success: false,
- message: "You are not enrolled in this course",
+ message: "Student is not enrolled in the course",
});
}
@@ -61,15 +52,12 @@ exports.createRating = async (req, res) => {
// update course with this rating/review
const updatedCourseDetails = await Course.findByIdAndUpdate(
- courseId,
+ { _id: courseId },
{
$push: { ratingAndReviews: ratingAndReview._id },
},
{ new: true }
- )
- .populate("updatedCourseDetails")
- .exec();
- console.log(updatedCourseDetails);
+ );
// send response
return res.status(200).json({
@@ -137,6 +125,7 @@ exports.getAllRatingAndReview = async (req, res) => {
.populate({ path: "course", select: "courseName" })
.exec();
+ console.log("allReviews", allReviews);
if (!allReviews) {
return res.status(400).json({
success: false,
diff --git a/frontend/src/components/common/RatingStars.jsx b/frontend/src/components/common/RatingStars.jsx
new file mode 100644
index 0000000..ae53fe6
--- /dev/null
+++ b/frontend/src/components/common/RatingStars.jsx
@@ -0,0 +1,38 @@
+import { useEffect, useState } from "react"
+import {TiStarFullOutline, TiStarHalfOutline, TiStarOutline,} from "react-icons/ti"
+
+
+function RatingStars({ Review_Count, Star_Size }){
+ const [starCount, SetStarCount] = useState({
+ full: 0,
+ half: 0,
+ empty: 0,
+ })
+
+ useEffect(() => {
+ const wholeStars = Math.floor(Review_Count) || 0
+ SetStarCount({
+ full: wholeStars,
+ half: Number.isInteger(Review_Count) ? 0 : 1,
+ empty: Number.isInteger(Review_Count) ? 5 - wholeStars : 4 - wholeStars,
+ })
+ }, [Review_Count])
+
+
+ return (
+
+ {[...new Array(starCount.full)].map((_, i) => {
+ return
+ })}
+ {[...new Array(starCount.half)].map((_, i) => {
+ return
+ })}
+ {[...new Array(starCount.empty)].map((_, i) => {
+ return
+ })}
+
+ )
+}
+
+
+export default RatingStars
\ No newline at end of file
diff --git a/frontend/src/components/common/ReviewSlider.jsx b/frontend/src/components/common/ReviewSlider.jsx
new file mode 100644
index 0000000..0a40edd
--- /dev/null
+++ b/frontend/src/components/common/ReviewSlider.jsx
@@ -0,0 +1,99 @@
+import { useEffect, useState } from "react";
+import ReactStars from "react-rating-stars-component";
+
+import { Swiper, SwiperSlide } from "swiper/react"; // Import Swiper React components
+import "swiper/css"; // Import Swiper styles
+import "swiper/css/free-mode";
+import "swiper/css/pagination";
+import "../../App.css";
+import { FaStar } from "react-icons/fa"; // Icons
+
+import { apiConnector } from "../../services/apiconnector"; // Get apiFunction and the endpoint
+import { ratingsEndpoints } from "../../services/apis";
+
+function ReviewSlider() {
+ const [reviews, setReviews] = useState([]);
+ const truncateWords = 15;
+
+ useEffect(() => {
+ (async () => {
+ const { data } = await apiConnector(
+ "GET",
+ ratingsEndpoints.REVIEWS_DETAILS_API
+ );
+ if (data?.success) {
+ setReviews(data?.data);
+ }
+ })();
+ }, []);
+
+ return (
+
+
+
+ {reviews.map((review, i) => {
+ return (
+
+
+
+
+
+
+
{`${review?.user?.firstName} ${review?.user?.lastName}`}
+
+ {" "}
+ {review?.course?.courseName}{" "}
+
+
+
+
+
+ {review?.review.split(" ").length > truncateWords
+ ? `${review?.review
+ .split(" ")
+ .slice(0, truncateWords)
+ .join(" ")} ...`
+ : `${review?.review}`}
+
+
+
+
+ {" "}
+ {review.rating.toFixed(1)}{" "}
+
+ }
+ fullIcon={}
+ />
+
+
+
+ );
+ })}
+
+
+
+ );
+}
+
+export default ReviewSlider;
diff --git a/frontend/src/hooks/useRouteMatch.js b/frontend/src/hooks/useRouteMatch.js
new file mode 100644
index 0000000..34b5678
--- /dev/null
+++ b/frontend/src/hooks/useRouteMatch.js
@@ -0,0 +1,8 @@
+import { useLocation, matchPath } from "react-router-dom";
+
+export default function useRouteMatch(path) {
+ const location = useLocation();
+ return matchPath(location.pathname, { path });
+}
+
+// this custom hook check if current location is same as path or not;
\ No newline at end of file
diff --git a/frontend/src/pages/About.jsx b/frontend/src/pages/About.jsx
index f897c07..49aa5df 100644
--- a/frontend/src/pages/About.jsx
+++ b/frontend/src/pages/About.jsx
@@ -2,13 +2,12 @@ import FoundingStory from "../assets/Images/FoundingStory.png";
import BannerImage1 from "../assets/Images/aboutus1.webp";
import BannerImage2 from "../assets/Images/aboutus2.webp";
import BannerImage3 from "../assets/Images/aboutus3.webp";
-
import ContactFormSection from "../components/core/AboutPage/ContactFormSection.jsx";
import LearningGrid from "../components/core/AboutPage/LearningGrid";
import Quote from "../components/core/AboutPage/Quote";
import StatsComponenet from "../components/core/AboutPage/Stats";
import HighlightText from "../components/core/HomePage/HighlightText";
-// import ReviewSlider from "../components/common/ReviewSlider";
+import ReviewSlider from "../components/common/ReviewSlider";
import Footer from "../components/common/Footer";
const About = () => {
@@ -128,7 +127,7 @@ const About = () => {
{" "}
Reviews from other learners{" "}
- {/* */}
+
diff --git a/frontend/src/pages/Contact.jsx b/frontend/src/pages/Contact.jsx
index 0dd376a..779a18a 100644
--- a/frontend/src/pages/Contact.jsx
+++ b/frontend/src/pages/Contact.jsx
@@ -1,7 +1,7 @@
import Footer from "../components/common/Footer";
import ContactDetails from "../components/ContactPage/ContactDetails";
import ContactForm from "../components/ContactPage/ContactForm";
-// import ReviewSlider from "../components/common/ReviewSlider"
+import ReviewSlider from "../components/common/ReviewSlider"
const Contact = () => {
return (
@@ -24,7 +24,7 @@ const Contact = () => {
{" "}
Reviews from other learners{" "}
- {/* */}
+
diff --git a/frontend/src/pages/Home.jsx b/frontend/src/pages/Home.jsx
index 83ab7ea..f97b8aa 100644
--- a/frontend/src/pages/Home.jsx
+++ b/frontend/src/pages/Home.jsx
@@ -9,7 +9,7 @@ import Footer from "../components/common/Footer";
import InstructorSection from "../components/core/HomePage/InstructorSection";
import LearningLanguageSection from "../components/core/HomePage/LearningLanguageSection";
import TimelineSection from "../components/core/HomePage/TimelineSection";
-// import ReviewSlider from "../components/common/ReviewSlider";
+import ReviewSlider from "../components/common/ReviewSlider";
function Home() {
return (
@@ -172,7 +172,7 @@ function Home() {
Reviews from Other Learners{" "}
{/* Review Slider here */}
- {/* */}
+
{/* Footer */}
diff --git a/frontend/src/pages/ViewCourse.jsx b/frontend/src/pages/ViewCourse.jsx
new file mode 100644
index 0000000..7bee7bf
--- /dev/null
+++ b/frontend/src/pages/ViewCourse.jsx
@@ -0,0 +1,50 @@
+import { useEffect, useState } from "react";
+import { useDispatch, useSelector } from "react-redux";
+import { Outlet, useParams } from "react-router-dom";
+
+import CourseReviewModal from "../components/core/ViewCourse/CourseReviewModal";
+import VideoDetailsSidebar from "../components/core/ViewCourse/VideoDetailsSidebar";
+import { getFullDetailsOfCourse } from "../services/operations/courseDetailsAPI";
+import {
+ setCompletedLectures,
+ setCourseSectionData,
+ setEntireCourseData,
+ setTotalNoOfLectures,
+} from "../slices/viewCourseSlice";
+
+export default function ViewCourse() {
+ const { courseId } = useParams();
+ const { token } = useSelector((state) => state.auth);
+ const dispatch = useDispatch();
+ const [reviewModal, setReviewModal] = useState(false);
+
+ useEffect(() => {
+ (async () => {
+ const courseData = await getFullDetailsOfCourse(courseId, token);
+ dispatch(setCourseSectionData(courseData.courseDetails.courseContent));
+ dispatch(setEntireCourseData(courseData.courseDetails));
+ dispatch(setCompletedLectures(courseData.completedVideos));
+ let lectures = 0;
+ courseData?.courseDetails?.courseContent?.forEach((sec) => {
+ lectures += sec.subSections.length;
+ });
+ dispatch(setTotalNoOfLectures(lectures));
+ })();
+ }, []);
+
+ return (
+ <>
+
+ {reviewModal && }{" "}
+ {/* when we open reviewModal or click on review then CourseReviewModal will be active */}
+ >
+ );
+}