mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-06-05 08:42:02 +00:00
added course header with back button, integrated into top nav when on course pages, polishing course and lesson pages styles
This commit is contained in:
parent
b50aa9286a
commit
a924cc9436
113
src/components/content/courses/CourseHeader.js
Normal file
113
src/components/content/courses/CourseHeader.js
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Tag } from 'primereact/tag';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
import GenericButton from '@/components/buttons/GenericButton';
|
||||||
|
import Image from 'next/image';
|
||||||
|
import 'primeicons/primeicons.css';
|
||||||
|
|
||||||
|
const CourseHeader = ({
|
||||||
|
course,
|
||||||
|
isMobileView,
|
||||||
|
isCompleted,
|
||||||
|
navbarHeight,
|
||||||
|
isNavbarMode = false
|
||||||
|
}) => {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
// Handle back button navigation
|
||||||
|
const handleBackNavigation = () => {
|
||||||
|
const { active, slug } = router.query;
|
||||||
|
|
||||||
|
// If we're on a specific lesson (has active param), remove it and stay on course page
|
||||||
|
if (active !== undefined) {
|
||||||
|
router.push(`/course/${slug}`, undefined, { shallow: true });
|
||||||
|
} else {
|
||||||
|
// If we're on the main course page (no active param), go back to previous page
|
||||||
|
router.push('/');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!course) return null;
|
||||||
|
|
||||||
|
// Navbar mode - compact version for the top navbar
|
||||||
|
if (isNavbarMode) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex items-center cursor-pointer hover:opacity-90"
|
||||||
|
onClick={() => router.push(`/course/${router.query.slug}`)}
|
||||||
|
>
|
||||||
|
<GenericButton
|
||||||
|
icon="pi pi-arrow-left"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
router.push('/');
|
||||||
|
}}
|
||||||
|
className="mr-2 pl-0 p-button-rounded p-button-text text-gray-300 hover:text-white"
|
||||||
|
rounded={true}
|
||||||
|
text={true}
|
||||||
|
aria-label="Go back to home"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{course.image && (
|
||||||
|
<div className="relative h-8 w-8 mr-3 rounded-md overflow-hidden flex-shrink-0 border border-gray-700/50">
|
||||||
|
<img
|
||||||
|
src={course.image}
|
||||||
|
alt={course.name}
|
||||||
|
className="object-cover w-full h-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex items-center">
|
||||||
|
<h1 className={`text-white font-semibold truncate ${isMobileView ? 'text-base max-w-[120px]' : 'text-lg max-w-[240px]'}`}>
|
||||||
|
{course.name}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
{isCompleted && !isMobileView && (
|
||||||
|
<Tag severity="success" value="Completed" size="small" className="ml-2 py-0.5 text-xs" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard mode - for course page content
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="bg-transparent backdrop-blur-sm mb-0 p-3 px-4 sticky z-20 flex items-center justify-between"
|
||||||
|
style={{ top: `${navbarHeight}px` }}
|
||||||
|
>
|
||||||
|
<div className="flex items-center max-w-[80%]">
|
||||||
|
<GenericButton
|
||||||
|
icon="pi pi-arrow-left"
|
||||||
|
onClick={handleBackNavigation}
|
||||||
|
className="mr-3 p-button-rounded p-button-text text-gray-300 hover:text-white"
|
||||||
|
tooltip="Go back"
|
||||||
|
tooltipOptions={{ position: 'bottom' }}
|
||||||
|
rounded={true}
|
||||||
|
text={true}
|
||||||
|
aria-label="Go back"
|
||||||
|
/>
|
||||||
|
{!isMobileView && course.image && (
|
||||||
|
<div className="relative w-8 h-8 mr-3 rounded-md overflow-hidden flex-shrink-0 border border-gray-700/50">
|
||||||
|
<img
|
||||||
|
src={course.image}
|
||||||
|
alt={course.name}
|
||||||
|
className="object-cover w-full h-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<h1 className={`font-medium text-gray-100 ${isMobileView ? 'text-sm' : 'text-base'} truncate`}>
|
||||||
|
{course.name}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center">
|
||||||
|
{isCompleted && (
|
||||||
|
<Tag severity="success" value="Completed" size="small" className="ml-2 py-1 text-xs" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CourseHeader;
|
@ -4,6 +4,7 @@ import { Button } from 'primereact/button';
|
|||||||
import { Sidebar } from 'primereact/sidebar';
|
import { Sidebar } from 'primereact/sidebar';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { useImageProxy } from '@/hooks/useImageProxy';
|
import { useImageProxy } from '@/hooks/useImageProxy';
|
||||||
|
import GenericButton from '@/components/buttons/GenericButton';
|
||||||
|
|
||||||
const CourseSidebar = ({
|
const CourseSidebar = ({
|
||||||
lessons,
|
lessons,
|
||||||
@ -18,6 +19,7 @@ const CourseSidebar = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { returnImageProxy } = useImageProxy();
|
const { returnImageProxy } = useImageProxy();
|
||||||
const [visible, setVisible] = useState(true);
|
const [visible, setVisible] = useState(true);
|
||||||
|
const navbarHeight = 60; // Match the navbar height
|
||||||
|
|
||||||
// Sync with parent state if provided
|
// Sync with parent state if provided
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -83,16 +85,17 @@ const CourseSidebar = ({
|
|||||||
|
|
||||||
// Sidebar content component for reuse
|
// Sidebar content component for reuse
|
||||||
const SidebarContent = () => (
|
const SidebarContent = () => (
|
||||||
<div className="flex flex-col h-full bg-gray-800 text-[#f8f8ff] px-4 py-4">
|
<div className="flex flex-col h-full bg-gray-800 text-[#f8f8ff] pl-3 py-4">
|
||||||
<div className="flex items-center justify-between border-b border-gray-700 pb-4 mb-4">
|
<div className="flex items-center justify-between border-b border-gray-700 pb-4 mb-4">
|
||||||
<h2 className="font-bold text-white text-lg">Course Lessons</h2>
|
<h2 className="font-bold text-white text-lg">Course Lessons</h2>
|
||||||
{visible && !hideToggleButton && !isMobileView && (
|
{visible && !hideToggleButton && !isMobileView && (
|
||||||
<Button
|
<GenericButton
|
||||||
icon="pi pi-times"
|
icon="pi pi-times"
|
||||||
onClick={handleToggle}
|
onClick={handleToggle}
|
||||||
className="p-button-rounded p-button-text text-gray-300 hover:text-white p-button-sm"
|
className="p-button-rounded p-button-text text-gray-300 hover:text-white p-button-sm"
|
||||||
tooltip="Close sidebar"
|
tooltip="Close sidebar"
|
||||||
tooltipOptions={{ position: 'left' }}
|
tooltipOptions={{ position: 'left' }}
|
||||||
|
rounded={true}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -121,9 +124,12 @@ const CourseSidebar = ({
|
|||||||
transform: 'translateY(-50%)'
|
transform: 'translateY(-50%)'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<GenericButton
|
||||||
icon="pi pi-chevron-left"
|
icon="pi pi-chevron-left"
|
||||||
onClick={handleToggle}
|
onClick={handleToggle}
|
||||||
|
className="shadow-2xl border-0 rounded-r-none rounded-l-xl bg-blue-600 hover:bg-blue-700 pointer-events-auto"
|
||||||
|
tooltip="Show lessons"
|
||||||
|
tooltipOptions={{ position: 'left' }}
|
||||||
style={{
|
style={{
|
||||||
borderTopRightRadius: 0,
|
borderTopRightRadius: 0,
|
||||||
borderBottomRightRadius: 0,
|
borderBottomRightRadius: 0,
|
||||||
@ -131,12 +137,6 @@ const CourseSidebar = ({
|
|||||||
width: '3rem',
|
width: '3rem',
|
||||||
height: '5rem'
|
height: '5rem'
|
||||||
}}
|
}}
|
||||||
className="shadow-2xl border-0 rounded-r-none rounded-l-xl bg-blue-600 hover:bg-blue-700 pointer-events-auto"
|
|
||||||
tooltip="Show lessons"
|
|
||||||
tooltipOptions={{ position: 'left' }}
|
|
||||||
pt={{
|
|
||||||
icon: { className: 'font-bold text-lg' }
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -176,7 +176,8 @@ const CourseSidebar = ({
|
|||||||
visible ? 'w-80 opacity-100' : 'w-0 opacity-0 overflow-hidden'
|
visible ? 'w-80 opacity-100' : 'w-0 opacity-0 overflow-hidden'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="ml-2 w-80 h-[calc(100vh-400px)] sticky top-8 overflow-hidden rounded-lg border border-gray-800 shadow-md bg-gray-900">
|
<div className="ml-2 w-80 h-[calc(100vh-400px)] sticky overflow-hidden rounded-lg border border-gray-800 shadow-md bg-gray-900"
|
||||||
|
style={{ top: `${navbarHeight + 70}px` }}> {/* Adjusted to match new header spacing */}
|
||||||
<div className="h-full overflow-y-auto">
|
<div className="h-full overflow-y-auto">
|
||||||
<SidebarContent />
|
<SidebarContent />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { TabMenu } from 'primereact/tabmenu';
|
import { TabMenu } from 'primereact/tabmenu';
|
||||||
import { Button } from 'primereact/button';
|
import { Button } from 'primereact/button';
|
||||||
|
import GenericButton from '@/components/buttons/GenericButton';
|
||||||
|
|
||||||
export default function MenuTab({ items, activeIndex, onTabChange, sidebarVisible, onToggleSidebar, isMobileView = false }) {
|
export default function MenuTab({ items, activeIndex, onTabChange, sidebarVisible, onToggleSidebar, isMobileView = false }) {
|
||||||
return (
|
return (
|
||||||
@ -25,12 +26,12 @@ export default function MenuTab({ items, activeIndex, onTabChange, sidebarVisibl
|
|||||||
{/* Sidebar toggle button positioned at the far right - hidden on mobile */}
|
{/* Sidebar toggle button positioned at the far right - hidden on mobile */}
|
||||||
{!isMobileView && (
|
{!isMobileView && (
|
||||||
<div className="absolute right-2 top-0 flex items-center h-full">
|
<div className="absolute right-2 top-0 flex items-center h-full">
|
||||||
<Button
|
<GenericButton
|
||||||
icon={sidebarVisible
|
icon={sidebarVisible
|
||||||
? "pi pi-times"
|
? "pi pi-times"
|
||||||
: "pi pi-chevron-left"}
|
: "pi pi-chevron-left"}
|
||||||
onClick={onToggleSidebar}
|
onClick={onToggleSidebar}
|
||||||
className="p-button-rounded text-blue-400 hover:text-blue-500 hover:bg-blue-100/10"
|
outlined={true}
|
||||||
style={{
|
style={{
|
||||||
width: '2.5rem',
|
width: '2.5rem',
|
||||||
height: '2.5rem',
|
height: '2.5rem',
|
||||||
@ -41,9 +42,6 @@ export default function MenuTab({ items, activeIndex, onTabChange, sidebarVisibl
|
|||||||
tooltip={sidebarVisible ? "Hide lessons" : "Show lessons"}
|
tooltip={sidebarVisible ? "Hide lessons" : "Show lessons"}
|
||||||
tooltipOptions={{ position: 'bottom' }}
|
tooltipOptions={{ position: 'bottom' }}
|
||||||
aria-label="Toggle course lessons"
|
aria-label="Toggle course lessons"
|
||||||
pt={{
|
|
||||||
icon: { className: 'font-bold text-lg' }
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -8,6 +8,10 @@ import { useSession } from 'next-auth/react';
|
|||||||
import 'primereact/resources/primereact.min.css';
|
import 'primereact/resources/primereact.min.css';
|
||||||
import 'primeicons/primeicons.css';
|
import 'primeicons/primeicons.css';
|
||||||
import useWindowWidth from '@/hooks/useWindowWidth';
|
import useWindowWidth from '@/hooks/useWindowWidth';
|
||||||
|
import CourseHeader from '../content/courses/CourseHeader';
|
||||||
|
import { useNDKContext } from '@/context/NDKContext';
|
||||||
|
import { nip19 } from 'nostr-tools';
|
||||||
|
import { parseCourseEvent } from '@/utils/nostr';
|
||||||
|
|
||||||
const Navbar = () => {
|
const Navbar = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -17,6 +21,51 @@ const Navbar = () => {
|
|||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
const [showMobileSearch, setShowMobileSearch] = useState(false);
|
const [showMobileSearch, setShowMobileSearch] = useState(false);
|
||||||
const menu = useRef(null);
|
const menu = useRef(null);
|
||||||
|
const { ndk } = useNDKContext();
|
||||||
|
const [course, setCourse] = useState(null);
|
||||||
|
const [isCompleted, setIsCompleted] = useState(false);
|
||||||
|
|
||||||
|
// Check if we're on a course page
|
||||||
|
const isCoursePage = router.pathname.startsWith('/course/');
|
||||||
|
|
||||||
|
// Fetch course data when on a course page
|
||||||
|
useEffect(() => {
|
||||||
|
if (isCoursePage && router.isReady && ndk) {
|
||||||
|
const fetchCourse = async () => {
|
||||||
|
try {
|
||||||
|
const { slug } = router.query;
|
||||||
|
let identifier;
|
||||||
|
|
||||||
|
if (slug.includes('naddr')) {
|
||||||
|
const { data } = nip19.decode(slug);
|
||||||
|
identifier = data?.identifier;
|
||||||
|
} else {
|
||||||
|
identifier = slug;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (identifier) {
|
||||||
|
const event = await ndk.fetchEvent({ '#d': [identifier] });
|
||||||
|
if (event) {
|
||||||
|
const parsedCourse = parseCourseEvent(event);
|
||||||
|
setCourse(parsedCourse);
|
||||||
|
|
||||||
|
// Check if course is completed (simplified for nav display)
|
||||||
|
if (session?.user?.completedCourses?.includes(identifier)) {
|
||||||
|
setIsCompleted(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching course for navbar:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchCourse();
|
||||||
|
} else {
|
||||||
|
setCourse(null);
|
||||||
|
setIsCompleted(false);
|
||||||
|
}
|
||||||
|
}, [isCoursePage, router.isReady, router.query, ndk, session?.user?.completedCourses]);
|
||||||
|
|
||||||
// Lock/unlock body scroll when mobile search is shown/hidden
|
// Lock/unlock body scroll when mobile search is shown/hidden
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -65,21 +114,33 @@ const Navbar = () => {
|
|||||||
>
|
>
|
||||||
{/* Left section */}
|
{/* Left section */}
|
||||||
<div className="flex items-center flex-1">
|
<div className="flex items-center flex-1">
|
||||||
<div
|
{isCoursePage && course ? (
|
||||||
onClick={() => router.push('/')}
|
/* Course header in navbar mode */
|
||||||
className="flex flex-row items-center justify-center cursor-pointer hover:opacity-80"
|
<CourseHeader
|
||||||
>
|
course={course}
|
||||||
<Image
|
isMobileView={windowWidth <= 600}
|
||||||
alt="logo"
|
isCompleted={isCompleted}
|
||||||
src="/images/plebdevs-icon.png"
|
isNavbarMode={true}
|
||||||
width={50}
|
|
||||||
height={50}
|
|
||||||
className="rounded-full max-tab:hidden max-mob:hidden"
|
|
||||||
/>
|
/>
|
||||||
<h1 className="text-white text-xl font-semibold max-tab:text-2xl max-mob:text-2xl pb-1 pl-2">
|
) : (
|
||||||
PlebDevs
|
/* Regular PlebDevs branding */
|
||||||
</h1>
|
<div
|
||||||
</div>
|
onClick={() => router.push('/')}
|
||||||
|
className="flex flex-row items-center justify-center cursor-pointer hover:opacity-80"
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
alt="logo"
|
||||||
|
src="/images/plebdevs-icon.png"
|
||||||
|
width={50}
|
||||||
|
height={50}
|
||||||
|
className="rounded-full max-tab:hidden max-mob:hidden"
|
||||||
|
/>
|
||||||
|
<h1 className="text-white text-xl font-semibold max-tab:text-2xl max-mob:text-2xl pb-1 pl-2">
|
||||||
|
PlebDevs
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{windowWidth > 600 ? (
|
{windowWidth > 600 ? (
|
||||||
<div
|
<div
|
||||||
className={`ml-2 p-2 cursor-pointer transition-all duration-300 flex items-center justify-center ${isHovered ? 'bg-gray-700 rounded-full' : ''}`}
|
className={`ml-2 p-2 cursor-pointer transition-all duration-300 flex items-center justify-center ${isHovered ? 'bg-gray-700 rounded-full' : ''}`}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState, useCallback } from 'react';
|
import React, { useEffect, useState, useCallback, useMemo } from 'react';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { parseCourseEvent, parseEvent, findKind0Fields } from '@/utils/nostr';
|
import { parseCourseEvent, parseEvent, findKind0Fields } from '@/utils/nostr';
|
||||||
import CourseDetails from '@/components/content/courses/CourseDetails';
|
import CourseDetails from '@/components/content/courses/CourseDetails';
|
||||||
@ -6,6 +6,7 @@ import VideoLesson from '@/components/content/courses/VideoLesson';
|
|||||||
import DocumentLesson from '@/components/content/courses/DocumentLesson';
|
import DocumentLesson from '@/components/content/courses/DocumentLesson';
|
||||||
import CombinedLesson from '@/components/content/courses/CombinedLesson';
|
import CombinedLesson from '@/components/content/courses/CombinedLesson';
|
||||||
import CourseSidebar from '@/components/content/courses/CourseSidebar';
|
import CourseSidebar from '@/components/content/courses/CourseSidebar';
|
||||||
|
import CourseHeader from '@/components/content/courses/CourseHeader';
|
||||||
import { useNDKContext } from '@/context/NDKContext';
|
import { useNDKContext } from '@/context/NDKContext';
|
||||||
import { useSession } from 'next-auth/react';
|
import { useSession } from 'next-auth/react';
|
||||||
import { nip19 } from 'nostr-tools';
|
import { nip19 } from 'nostr-tools';
|
||||||
@ -187,7 +188,8 @@ const Course = () => {
|
|||||||
const [nAddress, setNAddress] = useState(null);
|
const [nAddress, setNAddress] = useState(null);
|
||||||
const windowWidth = useWindowWidth();
|
const windowWidth = useWindowWidth();
|
||||||
const isMobileView = windowWidth <= 968;
|
const isMobileView = windowWidth <= 968;
|
||||||
const [activeTab, setActiveTab] = useState('content'); // Default to content tab on mobile
|
const [activeTab, setActiveTab] = useState('overview'); // Default to overview tab
|
||||||
|
const navbarHeight = 60; // Match the height from Navbar component
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (router.isReady) {
|
if (router.isReady) {
|
||||||
@ -200,6 +202,24 @@ const Course = () => {
|
|||||||
}
|
}
|
||||||
}, [router.isReady, router.query.slug]);
|
}, [router.isReady, router.query.slug]);
|
||||||
|
|
||||||
|
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 => {
|
const setCompleted = useCallback(lessonId => {
|
||||||
setCompletedLessons(prev => [...prev, lessonId]);
|
setCompletedLessons(prev => [...prev, lessonId]);
|
||||||
}, []);
|
}, []);
|
||||||
@ -220,12 +240,14 @@ const Course = () => {
|
|||||||
paidCourse,
|
paidCourse,
|
||||||
loading: courseLoading,
|
loading: courseLoading,
|
||||||
} = useCourseData(ndk, fetchAuthor, router);
|
} = useCourseData(ndk, fetchAuthor, router);
|
||||||
|
|
||||||
const { lessons, uniqueLessons, setLessons } = useLessons(
|
const { lessons, uniqueLessons, setLessons } = useLessons(
|
||||||
ndk,
|
ndk,
|
||||||
fetchAuthor,
|
fetchAuthor,
|
||||||
lessonIds,
|
lessonIds,
|
||||||
course?.pubkey
|
course?.pubkey
|
||||||
);
|
);
|
||||||
|
|
||||||
const { decryptionPerformed, loading: decryptionLoading } = useDecryption(
|
const { decryptionPerformed, loading: decryptionLoading } = useDecryption(
|
||||||
session,
|
session,
|
||||||
paidCourse,
|
paidCourse,
|
||||||
@ -234,24 +256,13 @@ const Course = () => {
|
|||||||
setLessons
|
setLessons
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
// Check if course is completed - moved after course is initialized
|
||||||
if (router.isReady) {
|
const isCourseCompleted = useMemo(() => {
|
||||||
const { active } = router.query;
|
if (!course || !completedLessons.length) return false;
|
||||||
if (active !== undefined) {
|
// A course is completed if at least one lesson is completed
|
||||||
setActiveIndex(parseInt(active, 10));
|
// You can change this logic if needed (e.g., all lessons must be completed)
|
||||||
} else {
|
return completedLessons.length > 0;
|
||||||
setActiveIndex(0);
|
}, [completedLessons, course]);
|
||||||
}
|
|
||||||
|
|
||||||
// Auto-open sidebar on desktop, close on mobile
|
|
||||||
setSidebarVisible(!isMobileView);
|
|
||||||
|
|
||||||
// Reset to content tab when switching to mobile
|
|
||||||
if (isMobileView) {
|
|
||||||
setActiveTab('content');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [router.isReady, router.query, isMobileView]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (uniqueLessons.length > 0) {
|
if (uniqueLessons.length > 0) {
|
||||||
@ -367,7 +378,7 @@ const Course = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
items.push({
|
items.push({
|
||||||
label: 'Q&A',
|
label: 'Comments',
|
||||||
icon: 'pi pi-comments',
|
icon: 'pi pi-comments',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -387,7 +398,6 @@ const Course = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Render Course Overview section
|
// Render Course Overview section
|
||||||
const renderOverviewSection = () => {
|
const renderOverviewSection = () => {
|
||||||
// Get isCompleted status for use in the component
|
// Get isCompleted status for use in the component
|
||||||
@ -474,20 +484,13 @@ const Course = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* {course && paidCourse !== null && (
|
<div className="mx-auto px-8 max-mob:px-1 mb-12 mt-4">
|
||||||
<CourseDetails
|
|
||||||
processedEvent={course}
|
|
||||||
paidCourse={paidCourse}
|
|
||||||
lessons={uniqueLessons}
|
|
||||||
decryptionPerformed={decryptionPerformed}
|
|
||||||
handlePaymentSuccess={handlePaymentSuccess}
|
|
||||||
handlePaymentError={handlePaymentError}
|
|
||||||
/>
|
|
||||||
)} */}
|
|
||||||
|
|
||||||
<div className="mx-4 mb-12">
|
|
||||||
{/* Tab navigation using MenuTab component */}
|
{/* Tab navigation using MenuTab component */}
|
||||||
<div className="sticky top-0 z-10 pt-2 bg-transparent border-b border-gray-700">
|
<div className="sticky z-10 bg-transparent border-b border-gray-700/30"
|
||||||
|
style={{
|
||||||
|
top: `${navbarHeight}px`,
|
||||||
|
height: `${navbarHeight}px`
|
||||||
|
}}>
|
||||||
<MenuTab
|
<MenuTab
|
||||||
items={getTabItems()}
|
items={getTabItems()}
|
||||||
activeIndex={getActiveTabIndex()}
|
activeIndex={getActiveTabIndex()}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user