diff --git a/src/components/content/courses/CourseDetails.js b/src/components/content/courses/details/CourseDetails.js similarity index 98% rename from src/components/content/courses/CourseDetails.js rename to src/components/content/courses/details/CourseDetails.js index d15a11c..e1c3c83 100644 --- a/src/components/content/courses/CourseDetails.js +++ b/src/components/content/courses/details/CourseDetails.js @@ -19,7 +19,7 @@ import { ProgressSpinner } from 'primereact/progressspinner'; import { Toast } from 'primereact/toast'; // Import the desktop and mobile components -import DesktopCourseDetails from './DesktopCourseDetails'; +import DesktopCourseDetails from '@/components/content/courses/details/DesktopCourseDetails'; import MobileCourseDetails from './MobileCourseDetails'; export default function CourseDetails({ diff --git a/src/components/content/courses/DesktopCourseDetails.js b/src/components/content/courses/details/DesktopCourseDetails.js similarity index 100% rename from src/components/content/courses/DesktopCourseDetails.js rename to src/components/content/courses/details/DesktopCourseDetails.js diff --git a/src/components/content/courses/DraftCourseDetails.js b/src/components/content/courses/details/DraftCourseDetails.js similarity index 100% rename from src/components/content/courses/DraftCourseDetails.js rename to src/components/content/courses/details/DraftCourseDetails.js diff --git a/src/components/content/courses/DraftCourseLesson.js b/src/components/content/courses/details/DraftCourseLesson.js similarity index 100% rename from src/components/content/courses/DraftCourseLesson.js rename to src/components/content/courses/details/DraftCourseLesson.js diff --git a/src/components/content/courses/MobileCourseDetails.js b/src/components/content/courses/details/MobileCourseDetails.js similarity index 100% rename from src/components/content/courses/MobileCourseDetails.js rename to src/components/content/courses/details/MobileCourseDetails.js diff --git a/src/components/content/courses/CourseHeader.js b/src/components/content/courses/layout/CourseHeader.js similarity index 100% rename from src/components/content/courses/CourseHeader.js rename to src/components/content/courses/layout/CourseHeader.js diff --git a/src/components/content/courses/CourseSidebar.js b/src/components/content/courses/layout/CourseSidebar.js similarity index 100% rename from src/components/content/courses/CourseSidebar.js rename to src/components/content/courses/layout/CourseSidebar.js diff --git a/src/components/content/courses/CombinedLesson.js b/src/components/content/courses/lessons/CombinedLesson.js similarity index 100% rename from src/components/content/courses/CombinedLesson.js rename to src/components/content/courses/lessons/CombinedLesson.js diff --git a/src/components/content/courses/CourseLesson.js b/src/components/content/courses/lessons/CourseLesson.js similarity index 100% rename from src/components/content/courses/CourseLesson.js rename to src/components/content/courses/lessons/CourseLesson.js diff --git a/src/components/content/courses/DocumentLesson.js b/src/components/content/courses/lessons/DocumentLesson.js similarity index 100% rename from src/components/content/courses/DocumentLesson.js rename to src/components/content/courses/lessons/DocumentLesson.js diff --git a/src/components/content/courses/VideoLesson.js b/src/components/content/courses/lessons/VideoLesson.js similarity index 100% rename from src/components/content/courses/VideoLesson.js rename to src/components/content/courses/lessons/VideoLesson.js diff --git a/src/components/content/courses/tabs/CourseContent.js b/src/components/content/courses/tabs/CourseContent.js new file mode 100644 index 0000000..e4e7953 --- /dev/null +++ b/src/components/content/courses/tabs/CourseContent.js @@ -0,0 +1,82 @@ +import React from 'react'; +import VideoLesson from '@/components/content/courses/lessons/VideoLesson'; +import DocumentLesson from '@/components/content/courses/lessons/DocumentLesson'; +import CombinedLesson from '@/components/content/courses/lessons/CombinedLesson'; +import MarkdownDisplay from '@/components/markdown/MarkdownDisplay'; + +/** + * Component to display course content including lessons + */ +const CourseContent = ({ + lessons, + activeIndex, + course, + paidCourse, + decryptedLessonIds, + setCompleted +}) => { + const renderLesson = (lesson) => { + if (!lesson) return null; + + // Check if this specific lesson is decrypted + const lessonDecrypted = !paidCourse || decryptedLessonIds[lesson.id] || false; + + if (lesson.topics?.includes('video') && lesson.topics?.includes('document')) { + return ( + + ); + } else if (lesson.type === 'video' && !lesson.topics?.includes('document')) { + return ( + + ); + } else if (lesson.type === 'document' && !lesson.topics?.includes('video')) { + return ( + + ); + } + + return null; + }; + + return ( + <> + {lessons.length > 0 && lessons[activeIndex] ? ( +
+
+ {renderLesson(lessons[activeIndex])} +
+
+ ) : ( +
+

Select a lesson from the sidebar to begin learning.

+
+ )} + + {course?.content && ( +
+ +
+ )} + + ); +}; + +export default CourseContent; \ No newline at end of file diff --git a/src/components/content/courses/tabs/CourseOverview.js b/src/components/content/courses/tabs/CourseOverview.js new file mode 100644 index 0000000..67dd049 --- /dev/null +++ b/src/components/content/courses/tabs/CourseOverview.js @@ -0,0 +1,58 @@ +import React from 'react'; +import { Tag } from 'primereact/tag'; +import CourseDetails from '../details/CourseDetails'; + +/** + * Component to display course overview with details + */ +const CourseOverview = ({ + course, + paidCourse, + lessons, + decryptionPerformed, + handlePaymentSuccess, + handlePaymentError, + isMobileView, + completedLessons +}) => { + // Determine if course is completed + const isCompleted = completedLessons.length > 0; + + return ( +
+ {isMobileView && course && ( +
+ {/* Completed tag above image in mobile view */} + {isCompleted && ( +
+ +
+ )} + + {/* Course image */} + {course.image && ( +
+ {course.title} +
+ )} +
+ )} + +
+ ); +}; + +export default CourseOverview; \ No newline at end of file diff --git a/src/components/content/courses/tabs/CourseQA.js b/src/components/content/courses/tabs/CourseQA.js new file mode 100644 index 0000000..4be5783 --- /dev/null +++ b/src/components/content/courses/tabs/CourseQA.js @@ -0,0 +1,32 @@ +import React from 'react'; +import ZapThreadsWrapper from '@/components/ZapThreadsWrapper'; + +/** + * Component to display course comments and Q&A section + */ +const CourseQA = ({ nAddress, isAuthorized, nsec, npub }) => { + return ( +
+

Comments

+ {nAddress !== null && isAuthorized ? ( +
+ +
+ ) : ( +
+

+ Comments are only available to content purchasers, subscribers, and the content creator. +

+
+ )} +
+ ); +}; + +export default CourseQA; \ No newline at end of file diff --git a/src/components/navbar/Navbar.js b/src/components/navbar/Navbar.js index 9fc60c1..344d8f1 100644 --- a/src/components/navbar/Navbar.js +++ b/src/components/navbar/Navbar.js @@ -8,7 +8,7 @@ import { useSession } from 'next-auth/react'; import 'primereact/resources/primereact.min.css'; import 'primeicons/primeicons.css'; import useWindowWidth from '@/hooks/useWindowWidth'; -import CourseHeader from '../content/courses/CourseHeader'; +import CourseHeader from '../content/courses/layout/CourseHeader'; import { useNDKContext } from '@/context/NDKContext'; import { nip19 } from 'nostr-tools'; import { parseCourseEvent } from '@/utils/nostr'; diff --git a/src/hooks/courses/useCourseData.js b/src/hooks/courses/useCourseData.js index 0140066..c6a6663 100644 --- a/src/hooks/courses/useCourseData.js +++ b/src/hooks/courses/useCourseData.js @@ -1,7 +1,7 @@ -import { useEffect, useState } from 'react'; -import { parseCourseEvent } from '@/utils/nostr'; +import { useState, useEffect } from 'react'; import { nip19 } from 'nostr-tools'; -import { useToast } from '../useToast'; +import { parseCourseEvent } from '@/utils/nostr'; +import { useToast } from '@/hooks/useToast'; /** * Hook to fetch and manage course data @@ -21,7 +21,8 @@ const useCourseData = (ndk, fetchAuthor, router) => { if (!router.isReady) return; const { slug } = router.query; - + let id; + const fetchCourseId = async () => { if (slug.includes('naddr')) { const { data } = nip19.decode(slug); @@ -54,7 +55,7 @@ const useCourseData = (ndk, fetchAuthor, router) => { const initializeCourse = async () => { setLoading(true); - const id = await fetchCourseId(); + id = await fetchCourseId(); if (!id) { setLoading(false); return; diff --git a/src/hooks/courses/useCourseNavigation.js b/src/hooks/courses/useCourseNavigation.js new file mode 100644 index 0000000..8f502b4 --- /dev/null +++ b/src/hooks/courses/useCourseNavigation.js @@ -0,0 +1,142 @@ +import { useState, useEffect, useMemo } from 'react'; + +/** + * Hook to manage course navigation and tab logic + * @param {Object} router - Next.js router instance + * @param {Boolean} isMobileView - Whether the current view is mobile + * @returns {Object} Navigation state and functions + */ +const useCourseNavigation = (router, isMobileView) => { + const [activeIndex, setActiveIndex] = useState(0); + const [sidebarVisible, setSidebarVisible] = useState(false); + const [activeTab, setActiveTab] = useState('overview'); // Default to overview tab + + // Memoized function to get the tab map based on view mode + const tabMap = useMemo(() => { + const baseTabMap = ['overview', 'content', 'qa']; + if (isMobileView) { + const mobileTabMap = [...baseTabMap]; + mobileTabMap.splice(2, 0, 'lessons'); + return mobileTabMap; + } + return baseTabMap; + }, [isMobileView]); + + // Initialize navigation state based on router + useEffect(() => { + if (router.isReady) { + const { active } = router.query; + if (active !== undefined) { + setActiveIndex(parseInt(active, 10)); + // If we have an active lesson, switch to content tab + setActiveTab('content'); + } else { + setActiveIndex(0); + // Default to overview tab when no active parameter + setActiveTab('overview'); + } + + // Auto-open sidebar on desktop, close on mobile + setSidebarVisible(!isMobileView); + } + }, [router.isReady, router.query, isMobileView]); + + // Function to handle lesson selection + const handleLessonSelect = (index) => { + setActiveIndex(index); + router.push(`/course/${router.query.slug}?active=${index}`, undefined, { shallow: true }); + + // On mobile, switch to content tab after selection + if (isMobileView) { + setActiveTab('content'); + setSidebarVisible(false); + } + }; + + // Function to toggle tab + const toggleTab = (index) => { + const tabName = tabMap[index]; + setActiveTab(tabName); + + // Only show/hide sidebar on mobile - desktop keeps sidebar visible + if (isMobileView) { + setSidebarVisible(tabName === 'lessons'); + } + }; + + // Function to toggle sidebar visibility + const toggleSidebar = () => { + setSidebarVisible(!sidebarVisible); + }; + + // Map active tab name back to index for MenuTab + const getActiveTabIndex = () => { + return tabMap.indexOf(activeTab); + }; + + // Create tab items for MenuTab + const getTabItems = () => { + const items = [ + { + label: 'Overview', + icon: 'pi pi-home', + }, + { + label: 'Content', + icon: 'pi pi-book', + } + ]; + + // Add lessons tab only on mobile + if (isMobileView) { + items.push({ + label: 'Lessons', + icon: 'pi pi-list', + }); + } + + items.push({ + label: 'Comments', + icon: 'pi pi-comments', + }); + + return items; + }; + + // Add keyboard navigation support for tabs + useEffect(() => { + const handleKeyDown = (e) => { + if (e.key === 'ArrowRight') { + const currentIndex = getActiveTabIndex(); + const nextIndex = (currentIndex + 1) % tabMap.length; + toggleTab(nextIndex); + } else if (e.key === 'ArrowLeft') { + const currentIndex = getActiveTabIndex(); + const prevIndex = (currentIndex - 1 + tabMap.length) % tabMap.length; + toggleTab(prevIndex); + } + }; + + document.addEventListener('keydown', handleKeyDown); + return () => { + document.removeEventListener('keydown', handleKeyDown); + }; + }, [activeTab, tabMap]); + + return { + activeIndex, + setActiveIndex, + activeTab, + setActiveTab, + sidebarVisible, + setSidebarVisible, + handleLessonSelect, + toggleTab, + toggleSidebar, + getActiveTabIndex, + getTabItems, + tabMap + }; +}; + +export default useCourseNavigation; \ No newline at end of file diff --git a/src/hooks/courses/useLessons.js b/src/hooks/courses/useLessons.js index 2c80706..2e98ea9 100644 --- a/src/hooks/courses/useLessons.js +++ b/src/hooks/courses/useLessons.js @@ -30,7 +30,7 @@ const useLessons = (ndk, fetchAuthor, lessonIds, pubkey) => { const events = await ndk.fetchEvents(filter); const newLessons = []; - // Process events + // Process events (no need to check for duplicates here) for (const event of events) { const author = await fetchAuthor(event.pubkey); const parsedLesson = { ...parseEvent(event), author }; @@ -47,7 +47,7 @@ const useLessons = (ndk, fetchAuthor, lessonIds, pubkey) => { } }, [lessonIds, ndk, fetchAuthor, pubkey]); - // Deduplicate lessons + // Keep this deduplication logic using Map useEffect(() => { const newUniqueLessons = Array.from( new Map(lessons.map(lesson => [lesson.id, lesson])).values() diff --git a/src/pages/course/[slug]/draft/index.js b/src/pages/course/[slug]/draft/index.js index f7d0ef1..8fd1591 100644 --- a/src/pages/course/[slug]/draft/index.js +++ b/src/pages/course/[slug]/draft/index.js @@ -2,8 +2,8 @@ import React, { useEffect, useState, useCallback } from 'react'; import { useRouter } from 'next/router'; import axios from 'axios'; import { parseEvent, findKind0Fields } from '@/utils/nostr'; -import DraftCourseDetails from '@/components/content/courses/DraftCourseDetails'; -import DraftCourseLesson from '@/components/content/courses/DraftCourseLesson'; +import DraftCourseDetails from '@/components/content/courses/details/DraftCourseDetails'; +import DraftCourseLesson from '@/components/content/courses/details/DraftCourseLesson'; import { useNDKContext } from '@/context/NDKContext'; import { useSession } from 'next-auth/react'; import { useIsAdmin } from '@/hooks/useIsAdmin'; diff --git a/src/pages/course/[slug]/index.js b/src/pages/course/[slug]/index.js index c4700e7..eb7fe99 100644 --- a/src/pages/course/[slug]/index.js +++ b/src/pages/course/[slug]/index.js @@ -1,168 +1,55 @@ -import React, { useEffect, useState, useCallback, useMemo, useRef } from 'react'; +import React, { useEffect, useState, useCallback } from 'react'; import { useRouter } from 'next/router'; -import { parseCourseEvent, parseEvent, findKind0Fields } from '@/utils/nostr'; -import CourseDetails from '@/components/content/courses/CourseDetails'; -import VideoLesson from '@/components/content/courses/VideoLesson'; -import DocumentLesson from '@/components/content/courses/DocumentLesson'; -import CombinedLesson from '@/components/content/courses/CombinedLesson'; -import CourseSidebar from '@/components/content/courses/CourseSidebar'; +import { findKind0Fields } from '@/utils/nostr'; import { useNDKContext } from '@/context/NDKContext'; import { useSession } from 'next-auth/react'; import { nip19 } from 'nostr-tools'; import { useToast } from '@/hooks/useToast'; import { ProgressSpinner } from 'primereact/progressspinner'; -import { useDecryptContent } from '@/hooks/encryption/useDecryptContent'; + +// Hooks import useCourseDecryption from '@/hooks/encryption/useCourseDecryption'; -import ZapThreadsWrapper from '@/components/ZapThreadsWrapper'; -import appConfig from '@/config/appConfig'; +import useCourseData from '@/hooks/courses/useCourseData'; +import useLessons from '@/hooks/courses/useLessons'; +import useCourseNavigation from '@/hooks/courses/useCourseNavigation'; import useWindowWidth from '@/hooks/useWindowWidth'; + +// Components +import CourseSidebar from '@/components/content/courses/layout/CourseSidebar'; +import CourseContent from '@/components/content/courses/tabs/CourseContent'; +import CourseQA from '@/components/content/courses/tabs/CourseQA'; +import CourseOverview from '@/components/content/courses/tabs/CourseOverview'; import MenuTab from '@/components/menutab/MenuTab'; -import { Tag } from 'primereact/tag'; -import MarkdownDisplay from '@/components/markdown/MarkdownDisplay'; -const useCourseData = (ndk, fetchAuthor, router) => { - const [course, setCourse] = useState(null); - const [lessonIds, setLessonIds] = useState([]); - const [paidCourse, setPaidCourse] = useState(null); - const [loading, setLoading] = useState(true); - const { showToast } = useToast(); - - useEffect(() => { - if (!router.isReady) return; - - const { slug } = router.query; - let id; - - const fetchCourseId = async () => { - if (slug.includes('naddr')) { - const { data } = nip19.decode(slug); - if (!data?.identifier) { - showToast('error', 'Error', 'Resource not found'); - return null; - } - return data.identifier; - } else { - return slug; - } - }; - - const fetchCourse = async courseId => { - try { - await ndk.connect(); - const event = await ndk.fetchEvent({ '#d': [courseId] }); - if (!event) return null; - - const author = await fetchAuthor(event.pubkey); - const lessonIds = event.tags.filter(tag => tag[0] === 'a').map(tag => tag[1].split(':')[2]); - - const parsedCourse = { ...parseCourseEvent(event), author }; - return { parsedCourse, lessonIds }; - } catch (error) { - console.error('Error fetching event:', error); - return null; - } - }; - - const initializeCourse = async () => { - setLoading(true); - id = await fetchCourseId(); - if (!id) { - setLoading(false); - return; - } - - const courseData = await fetchCourse(id); - if (courseData) { - const { parsedCourse, lessonIds } = courseData; - setCourse(parsedCourse); - setLessonIds(lessonIds); - setPaidCourse(parsedCourse.price && parsedCourse.price > 0); - } - setLoading(false); - }; - - initializeCourse(); - }, [router.isReady, router.query, ndk, fetchAuthor, showToast]); - - return { course, lessonIds, paidCourse, loading }; -}; - -const useLessons = (ndk, fetchAuthor, lessonIds, pubkey) => { - const [lessons, setLessons] = useState([]); - const [uniqueLessons, setUniqueLessons] = useState([]); - const { showToast } = useToast(); - - useEffect(() => { - if (lessonIds.length > 0 && pubkey) { - const fetchLessons = async () => { - try { - await ndk.connect(); - - // Create a single filter with all lesson IDs to avoid multiple calls - const filter = { - '#d': lessonIds, - kinds: [30023, 30402], - authors: [pubkey], - }; - - const events = await ndk.fetchEvents(filter); - const newLessons = []; - - // Process events (no need to check for duplicates here) - for (const event of events) { - const author = await fetchAuthor(event.pubkey); - const parsedLesson = { ...parseEvent(event), author }; - newLessons.push(parsedLesson); - } - - setLessons(newLessons); - } catch (error) { - console.error('Error fetching events:', error); - } - }; - - fetchLessons(); - } - }, [lessonIds, ndk, fetchAuthor, pubkey]); - - // Keep this deduplication logic using Map - useEffect(() => { - const newUniqueLessons = Array.from( - new Map(lessons.map(lesson => [lesson.id, lesson])).values() - ); - setUniqueLessons(newUniqueLessons); - }, [lessons]); - - return { lessons, uniqueLessons, setLessons }; -}; +// Config +import appConfig from '@/config/appConfig'; const Course = () => { const router = useRouter(); const { ndk, addSigner } = useNDKContext(); const { data: session, update } = useSession(); const { showToast } = useToast(); - const [activeIndex, setActiveIndex] = useState(0); const [completedLessons, setCompletedLessons] = useState([]); const [nAddresses, setNAddresses] = useState({}); const [nsec, setNsec] = useState(null); const [npub, setNpub] = useState(null); - const [sidebarVisible, setSidebarVisible] = useState(false); const [nAddress, setNAddress] = useState(null); const windowWidth = useWindowWidth(); const isMobileView = windowWidth <= 968; - const [activeTab, setActiveTab] = useState('overview'); // Default to overview tab const navbarHeight = 60; // Match the height from Navbar component - // Memoized function to get the tab map based on view mode - const getTabMap = useMemo(() => { - const baseTabMap = ['overview', 'content', 'qa']; - if (isMobileView) { - const mobileTabMap = [...baseTabMap]; - mobileTabMap.splice(2, 0, 'lessons'); - return mobileTabMap; - } - return baseTabMap; - }, [isMobileView]); + // Use our navigation hook + const { + activeIndex, + activeTab, + sidebarVisible, + setSidebarVisible, + handleLessonSelect, + toggleTab, + toggleSidebar, + getActiveTabIndex, + getTabItems, + } = useCourseNavigation(router, isMobileView); useEffect(() => { if (router.isReady && router.query.slug) { @@ -179,24 +66,6 @@ const Course = () => { } }, [router.isReady, router.query.slug, showToast, router]); - useEffect(() => { - if (router.isReady) { - const { active } = router.query; - if (active !== undefined) { - setActiveIndex(parseInt(active, 10)); - // If we have an active lesson, switch to content tab - setActiveTab('content'); - } else { - setActiveIndex(0); - // Default to overview tab when no active parameter - setActiveTab('overview'); - } - - // Auto-open sidebar on desktop, close on mobile - setSidebarVisible(!isMobileView); - } - }, [router.isReady, router.query, isMobileView]); - const setCompleted = useCallback(lessonId => { setCompletedLessons(prev => [...prev, lessonId]); }, []); @@ -268,18 +137,7 @@ const Course = () => { session?.user?.role?.subscribed || session?.user?.pubkey === course?.pubkey || !paidCourse || - session?.user?.purchased?.some(purchase => purchase.courseId === course?.d) - - const handleLessonSelect = index => { - setActiveIndex(index); - router.push(`/course/${router.query.slug}?active=${index}`, undefined, { shallow: true }); - - // On mobile, switch to content tab after selection - if (isMobileView) { - setActiveTab('content'); - setSidebarVisible(false); - } - }; + session?.user?.purchased?.some(purchase => purchase.courseId === course?.d); const handlePaymentSuccess = async response => { if (response && response?.preimage) { @@ -298,141 +156,6 @@ const Course = () => { ); }; - const toggleTab = (index) => { - const tabName = getTabMap[index]; - setActiveTab(tabName); - - // Only show/hide sidebar on mobile - desktop keeps sidebar visible - if (isMobileView) { - setSidebarVisible(tabName === 'lessons'); - } - }; - - const handleToggleSidebar = () => { - setSidebarVisible(!sidebarVisible); - }; - - // Map active tab name back to index for MenuTab - const getActiveTabIndex = () => { - return getTabMap.indexOf(activeTab); - }; - - // Create tab items for MenuTab - const getTabItems = () => { - const items = [ - { - label: 'Overview', - icon: 'pi pi-home', - }, - { - label: 'Content', - icon: 'pi pi-book', - } - ]; - - // Add lessons tab only on mobile - if (isMobileView) { - items.push({ - label: 'Lessons', - icon: 'pi pi-list', - }); - } - - items.push({ - label: 'Comments', - icon: 'pi pi-comments', - }); - - return items; - }; - - // Add keyboard navigation support for tabs - useEffect(() => { - const handleKeyDown = (e) => { - if (e.key === 'ArrowRight') { - const currentIndex = getActiveTabIndex(); - const nextIndex = (currentIndex + 1) % getTabMap.length; - toggleTab(nextIndex); - } else if (e.key === 'ArrowLeft') { - const currentIndex = getActiveTabIndex(); - const prevIndex = (currentIndex - 1 + getTabMap.length) % getTabMap.length; - toggleTab(prevIndex); - } - }; - - document.addEventListener('keydown', handleKeyDown); - return () => { - document.removeEventListener('keydown', handleKeyDown); - }; - }, [activeTab, getTabMap, toggleTab]); - - // Render the QA section (empty for now) - const renderQASection = () => { - return ( -
-

Comments

- {nAddress !== null && isAuthorized ? ( -
- -
- ) : ( -
-

- Comments are only available to content purchasers, subscribers, and the content creator. -

-
- )} -
- ); - }; - // Render Course Overview section - const renderOverviewSection = () => { - // Get isCompleted status for use in the component - const isCompleted = completedLessons.length > 0; - - return ( -
- {isMobileView && course && ( -
- {/* Completed tag above image in mobile view */} - {isCompleted && ( -
- -
- )} - - {/* Course image */} - {course.image && ( -
- {course.title} -
- )} -
- )} - -
- ); - }; - if (courseLoading || decryptionLoading) { return (
@@ -441,45 +164,6 @@ const Course = () => { ); } - const renderLesson = lesson => { - if (!lesson) return null; - - // Check if this specific lesson is decrypted - const lessonDecrypted = !paidCourse || decryptedLessonIds[lesson.id] || false; - - if (lesson.topics?.includes('video') && lesson.topics?.includes('document')) { - return ( - - ); - } else if (lesson.type === 'video' && !lesson.topics?.includes('document')) { - return ( - - ); - } else if (lesson.type === 'document' && !lesson.topics?.includes('video')) { - return ( - - ); - } - }; - return ( <>
@@ -494,45 +178,50 @@ const Course = () => { activeIndex={getActiveTabIndex()} onTabChange={(index) => toggleTab(index)} sidebarVisible={sidebarVisible} - onToggleSidebar={handleToggleSidebar} + onToggleSidebar={toggleSidebar} isMobileView={isMobileView} />
- {/* Revised layout structure to prevent content flexing */} + {/* Main content area with fixed width */}
- {/* Main content area with fixed width */}
+ {/* Overview tab content */}
- {renderOverviewSection()} +
{/* Content tab content */}
- {uniqueLessons.length > 0 && uniqueLessons[activeIndex] ? ( -
-
- {renderLesson(uniqueLessons[activeIndex])} -
-
- ) : ( -
-

Select a lesson from the sidebar to begin learning.

-
- )} - - {course?.content && ( -
- -
- )} +
{/* QA tab content */}
- {renderQASection()} +
@@ -556,12 +245,7 @@ const Course = () => { { - handleLessonSelect(index); - if (isMobileView) { - setActiveTab('content'); // Use the tab name directly - } - }} + onLessonSelect={handleLessonSelect} completedLessons={completedLessons} isMobileView={isMobileView} sidebarVisible={sidebarVisible} @@ -577,17 +261,12 @@ const Course = () => { { - handleLessonSelect(index); - if (isMobileView) { - setActiveTab('content'); // Use the tab name directly - } - }} + onLessonSelect={handleLessonSelect} completedLessons={completedLessons} isMobileView={isMobileView} onClose={() => { setSidebarVisible(false); - setActiveTab('content'); + toggleTab(getActiveTabIndex()); }} sidebarVisible={sidebarVisible} setSidebarVisible={setSidebarVisible}