diff --git a/frontend/src/pages/Academy/Courses/CourseDetail.jsx b/frontend/src/pages/Academy/Courses/CourseDetail.jsx
index e19f383..0b011f6 100644
--- a/frontend/src/pages/Academy/Courses/CourseDetail.jsx
+++ b/frontend/src/pages/Academy/Courses/CourseDetail.jsx
@@ -1,7 +1,13 @@
/* global process */
import React, { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
-import { FiArrowLeft } from 'react-icons/fi';
+import {
+ FiArrowLeft,
+ FiCheck,
+ FiChevronDown,
+ FiPlay,
+ FiStar,
+} from 'react-icons/fi';
// ------------------------------
// STRIPE IMPORTS
@@ -14,8 +20,6 @@ import { loadStripe } from "@stripe/stripe-js";
// ------------------------------
import CheckoutForm from "../../../components/Shared/CheckoutForm";
-import { FiClock, FiDollarSign } from 'react-icons/fi';
-
// ------------------------------
// STRIPE INITIALIZATION
// ------------------------------
@@ -191,18 +195,39 @@ function CourseDetail() {
// ------------------------------
// HELPERS
// ------------------------------
- const _getCoursePrice = (c) => {
- if (!c) return 'Free';
- if (c.isLiteVersion) return 'Free (Lite)';
- if (c.priceAmount && c.priceAmount > 0) {
- return `$${c.priceAmount}`;
+ const getShortDescription = (value) => {
+ const text = String(value || '').trim();
+ if (!text) return 'Build your freelance career with practical, real-world guidance.';
+ const firstSentence = text.split(/(?<=[.!?])\s+/)[0] || text;
+ return firstSentence.length > 140 ? `${firstSentence.slice(0, 137).trimEnd()}...` : firstSentence;
+ };
+
+ const formatDate = (value) => {
+ if (!value) return '00/0000';
+ try {
+ return new Date(value).toLocaleDateString();
+ } catch {
+ return '00/0000';
}
- return 'Free';
};
- const _formatDuration = (duration) => {
- if (!duration) return 'N/A';
- return duration;
+ const formatMinutes = (value) => {
+ const minutes = Number(value || 0);
+ if (!Number.isFinite(minutes) || minutes <= 0) return null;
+ const hours = Math.floor(minutes / 60);
+ const mins = Math.round(minutes % 60);
+ return `${hours}h ${String(mins).padStart(2, '0')}m`;
+ };
+
+ const getTotalLectureCount = (modules = []) => (
+ modules.reduce((total, moduleItem) => total + (moduleItem?.learningPoints?.length || 0), 0)
+ );
+
+ const handleModuleKeyDown = (event, moduleKey) => {
+ if (event.key === 'Enter' || event.key === ' ') {
+ event.preventDefault();
+ toggleModule(moduleKey);
+ }
};
// ------------------------------
@@ -240,130 +265,241 @@ function CourseDetail() {
// ------------------------------
// MAIN RENDER
// ------------------------------
- const _publishedDate = course?.createdAt
- ? new Date(course.createdAt).toLocaleDateString()
- : null;
+ const modules = Array.isArray(course?.modules) ? course.modules : [];
+ const totalLectures = getTotalLectureCount(modules);
+ const totalLength = formatMinutes(course?.estimatedMinutes) || course?.duration || '00h 00m';
+ const priceAmount = Number(course?.priceAmount ?? course?.pricing?.amount ?? 0);
+ const isFree = Boolean(course?.isFree) || course?.isLiteVersion || priceAmount === 0;
+ const hasSubscription = course?.subscription?.isSubscriptionCourse === true || course?.subscription?.isSubscriptionCourse === 'true';
+ const tierLabel = course?.subscription?.tier || 'Standard';
+ const shortDescription = getShortDescription(course?.description);
return (
-
+
-