diff --git a/src/components/CourseView.tsx b/src/components/CourseView.tsx
index 345705e97..675c9c361 100644
--- a/src/components/CourseView.tsx
+++ b/src/components/CourseView.tsx
@@ -1,7 +1,6 @@
import { Folder } from '@/db/course';
import { ContentRenderer } from './admin/ContentRenderer';
import { FolderView } from './FolderView';
-import { Sidebar } from './Sidebar';
import { NotionRenderer } from './NotionRenderer';
import { getFolderPercentCompleted } from '@/lib/utils';
import Comments from './comment/Comments';
@@ -28,65 +27,61 @@ export const CourseView = ({
possiblePath: string;
}) => {
return (
-
-
-
-
-
-
-
- {contentType === 'notion' ? (
-
- ) : null}
-
- {contentType === 'video' ? (
-
- ) : null}
- {(contentType === 'video' || contentType === 'notion') && (
-
- )}
- {contentType === 'folder' ? (
-
({
- title: x?.title || '',
- image: x?.thumbnail || '',
- type: x?.type || 'folder',
- id: x?.id || 0,
- markAsCompleted: x?.videoProgress?.markAsCompleted || false,
- percentComplete: getFolderPercentCompleted(x?.children),
- videoFullDuration: x?.videoProgress?.videoFullDuration || 0,
- duration: x?.videoProgress?.duration || 0,
- }))}
- courseId={parseInt(course.id, 10)}
- />
- ) : null}
+ <>
+
+
-
+ {contentType === 'notion' ? (
+
+ ) : null}
+
+ {contentType === 'video' ? (
+
+ ) : null}
+ {(contentType === 'video' || contentType === 'notion') && (
+
+ )}
+ {contentType === 'folder' ? (
+
({
+ title: x?.title || '',
+ image: x?.thumbnail || '',
+ type: x?.type || 'folder',
+ id: x?.id || 0,
+ markAsCompleted: x?.videoProgress?.markAsCompleted || false,
+ percentComplete: getFolderPercentCompleted(x?.children),
+ videoFullDuration: x?.videoProgress?.videoFullDuration || 0,
+ duration: x?.videoProgress?.duration || 0,
+ }))}
+ courseId={parseInt(course.id, 10)}
+ />
+ ) : null}
+ >
);
};
diff --git a/src/components/FolderView.tsx b/src/components/FolderView.tsx
index ec8e6be2a..da3315cb6 100644
--- a/src/components/FolderView.tsx
+++ b/src/components/FolderView.tsx
@@ -61,6 +61,7 @@ export const FolderView = ({
percentComplete={content.percentComplete}
videoProgressPercent={videoProgressPercent}
bookmark={content.bookmark}
+ contentDuration={content.videoFullDuration}
/>
);
})}
diff --git a/src/components/PercentageComplete.tsx b/src/components/PercentageComplete.tsx
index af267691b..a457234b6 100644
--- a/src/components/PercentageComplete.tsx
+++ b/src/components/PercentageComplete.tsx
@@ -3,7 +3,7 @@ import React from 'react';
const PercentageComplete = ({ percent }: { percent: number }) => {
return (
{`${percent}% completed`}
diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx
index 6bdac5d62..7a1a01552 100644
--- a/src/components/Sidebar.tsx
+++ b/src/components/Sidebar.tsx
@@ -1,5 +1,5 @@
'use client';
-import { useRouter } from 'next/navigation';
+import { usePathname, useRouter } from 'next/navigation';
import {
Accordion,
AccordionContent,
@@ -23,7 +23,34 @@ export function Sidebar({
courseId: string;
}) {
const router = useRouter();
+ const pathName = usePathname();
+
const [sidebarOpen, setSidebarOpen] = useRecoilState(sidebarOpenAtom);
+ const [currentActiveContentIds, setCurrentActiveContentIds] = useState<
+ number[]
+ >([]);
+
+ useEffect(() => {
+ const urlRegex = /\/courses\/.*./;
+ const courseUrlRegex = /\/courses\/\d+((?:\/\d+)+)/;
+
+ if (urlRegex.test(pathName)) {
+ const matchArray = pathName.match(courseUrlRegex);
+ let currentUrlContentId;
+ // if matchArray is not null
+ if (matchArray) {
+ const urlPathString = matchArray[1];
+ currentUrlContentId = Number(
+ urlPathString.slice(urlPathString.length - 1),
+ ); // get last content id from pathString e.g '/1/2' => 2 (number)
+ }
+ const pathArray = findPathToContent(
+ fullCourseContent,
+ currentUrlContentId,
+ );
+ setCurrentActiveContentIds(pathArray);
+ }
+ }, [pathName]);
useEffect(() => {
if (window.innerWidth < 500) {
@@ -65,13 +92,20 @@ export function Sidebar({
const renderContent = (contents: any) => {
return contents.map((content: any) => {
+ const isActiveContent = currentActiveContentIds?.some(
+ (id) => content.id === id,
+ );
if (content.children && content.children.length > 0) {
// This is a folder with children
return (
{content.title}
@@ -87,7 +121,11 @@ export function Sidebar({
return (
{
navigateToContent(content.id);
}}
@@ -122,7 +160,7 @@ export function Sidebar({
}
return (
-
+
{/*
{
@@ -157,16 +195,16 @@ export function ToggleButton({
);
@@ -193,8 +231,9 @@ function GoBackButton() {
return (
{/* Your component content */}
-
- Go Back
+
+ {' '}
+ Go Back
);
diff --git a/src/components/Signin.tsx b/src/components/Signin.tsx
index c6c6a02e9..998dacda1 100644
--- a/src/components/Signin.tsx
+++ b/src/components/Signin.tsx
@@ -79,7 +79,7 @@ const Signin = () => {
Email is required
)}
-
+
Password
{
}}
/>
{isPasswordVisible ? (
diff --git a/src/components/VideoPlayer.tsx b/src/components/VideoPlayer.tsx
index ef1cbb434..92ef05e61 100644
--- a/src/components/VideoPlayer.tsx
+++ b/src/components/VideoPlayer.tsx
@@ -22,23 +22,23 @@ export const VideoPlayer = ({
}
const handleKeyPress = (event: any) => {
switch (event.code) {
- case 'Space': // Space bar for play/pause
- if (player.paused()) {
- player.play();
+ case 'Space': // Space bar for play/pause
+ if (player.paused()) {
+ player.play();
+ event.stopPropagation();
+ } else {
+ player.pause();
+ event.stopPropagation();
+ }
+ break;
+ case 'ArrowRight': // Right arrow for seeking forward 5 seconds
+ player.currentTime(player.currentTime() + 5);
event.stopPropagation();
- } else {
- player.pause();
+ break;
+ case 'ArrowLeft': // Left arrow for seeking backward 5 seconds
+ player.currentTime(player.currentTime() - 5);
event.stopPropagation();
- }
- break;
- case 'ArrowRight': // Right arrow for seeking forward 5 seconds
- player.currentTime(player.currentTime() + 5);
- event.stopPropagation();
- break;
- case 'ArrowLeft': // Left arrow for seeking backward 5 seconds
- player.currentTime(player.currentTime() - 5);
- event.stopPropagation();
- break;
+ break;
}
};
diff --git a/src/components/VideoPlayer2.tsx b/src/components/VideoPlayer2.tsx
index 59a295cf5..c142a354b 100644
--- a/src/components/VideoPlayer2.tsx
+++ b/src/components/VideoPlayer2.tsx
@@ -12,6 +12,7 @@ import 'videojs-seek-buttons';
import { handleMarkAsCompleted } from '@/lib/utils';
import { useSearchParams } from 'next/navigation';
import './QualitySelectorControllBar';
+import { YoutubeRenderer } from './YoutubeRenderer';
// todo correct types
interface VideoPlayerProps {
@@ -38,6 +39,7 @@ export const VideoPlayer: FunctionComponent = ({
const playerRef = useRef(null);
const [player, setPlayer] = useState(null);
const searchParams = useSearchParams();
+ const vidUrl = options.sources[0].src;
useEffect(() => {
const t = searchParams.get('timestamp');
if (contentId && player && !t) {
@@ -78,40 +80,40 @@ export const VideoPlayer: FunctionComponent = ({
const newIndexDown =
currentIndexDown !== 0 ? currentIndexDown - 1 : currentIndexDown;
switch (event.code) {
- case 'Period': // Increase playback speed
- player.playbackRate(PLAYBACK_RATES[newIndexPeriod]);
- event.stopPropagation();
- break;
- case 'Comma': // Decrease playback speed
- player.playbackRate(PLAYBACK_RATES[newIndexComma]);
- event.stopPropagation();
- break;
- case 'ArrowUp': // Increase volume
- videoRef.current?.children[0].children[6].children[3].classList.add(
- 'vjs-hover',
- );
- if (volumeSetTimeout !== null) clearTimeout(volumeSetTimeout);
- volumeSetTimeout = setTimeout(() => {
- videoRef.current?.children[0].children[6].children[3].classList.remove(
+ case 'Period': // Increase playback speed
+ player.playbackRate(PLAYBACK_RATES[newIndexPeriod]);
+ event.stopPropagation();
+ break;
+ case 'Comma': // Decrease playback speed
+ player.playbackRate(PLAYBACK_RATES[newIndexComma]);
+ event.stopPropagation();
+ break;
+ case 'ArrowUp': // Increase volume
+ videoRef.current?.children[0].children[6].children[3].classList.add(
'vjs-hover',
);
- }, 1000);
- player.volume(VOLUME_LEVELS[newIndexUp]);
- event.stopPropagation();
- break;
- case 'ArrowDown': // Decrease volume
- videoRef.current?.children[0].children[6].children[3].classList.add(
- 'vjs-hover',
- );
- if (volumeSetTimeout !== null) clearTimeout(volumeSetTimeout);
- volumeSetTimeout = setTimeout(() => {
- videoRef.current?.children[0].children[6].children[3].classList.remove(
+ if (volumeSetTimeout !== null) clearTimeout(volumeSetTimeout);
+ volumeSetTimeout = setTimeout(() => {
+ videoRef.current?.children[0].children[6].children[3].classList.remove(
+ 'vjs-hover',
+ );
+ }, 1000);
+ player.volume(VOLUME_LEVELS[newIndexUp]);
+ event.stopPropagation();
+ break;
+ case 'ArrowDown': // Decrease volume
+ videoRef.current?.children[0].children[6].children[3].classList.add(
'vjs-hover',
);
- }, 1000);
- player.volume(VOLUME_LEVELS[newIndexDown]);
- event.stopPropagation();
- break;
+ if (volumeSetTimeout !== null) clearTimeout(volumeSetTimeout);
+ volumeSetTimeout = setTimeout(() => {
+ videoRef.current?.children[0].children[6].children[3].classList.remove(
+ 'vjs-hover',
+ );
+ }, 1000);
+ player.volume(VOLUME_LEVELS[newIndexDown]);
+ event.stopPropagation();
+ break;
}
} else if (event.code === 'KeyT') {
player.playbackRate(2);
@@ -127,74 +129,74 @@ export const VideoPlayer: FunctionComponent = ({
return; // Do nothing if the active element is an input or textarea
}
switch (event.code) {
- case 'Space': // Space bar for play/pause
- if (player.paused()) {
- player.play();
+ case 'Space': // Space bar for play/pause
+ if (player.paused()) {
+ player.play();
+ event.stopPropagation();
+ } else {
+ player.pause();
+ event.stopPropagation();
+ }
+ event.preventDefault();
+ break;
+ case 'ArrowRight': // Right arrow for seeking forward 5 seconds
+ player.currentTime(player.currentTime() + 5);
event.stopPropagation();
- } else {
- player.pause();
+ break;
+ case 'ArrowLeft': // Left arrow for seeking backward 5 seconds
+ player.currentTime(player.currentTime() - 5);
event.stopPropagation();
- }
- event.preventDefault();
- break;
- case 'ArrowRight': // Right arrow for seeking forward 5 seconds
- player.currentTime(player.currentTime() + 5);
- event.stopPropagation();
- break;
- case 'ArrowLeft': // Left arrow for seeking backward 5 seconds
- player.currentTime(player.currentTime() - 5);
- event.stopPropagation();
- break;
- case 'KeyF': // F key for fullscreen
- if (player.isFullscreen_) document.exitFullscreen();
- else player.requestFullscreen();
- event.stopPropagation();
- break;
- case 'KeyR': // 'R' key to restart playback from the beginning
- player.currentTime(0);
- event.stopPropagation();
- break;
- case 'KeyM': // 'M' key to toggle mute/unmute
- if (player.volume() === 0) {
- player.volume(1);
- } else {
- player.volume(0);
- }
- event.stopPropagation();
- break;
- case 'KeyK': // 'K' key for play/pause toggle
- if (player.paused()) {
- player.play();
- } else {
- player.pause();
- }
- event.stopPropagation();
- break;
- case 'KeyJ': // 'J' key for seeking backward 10 seconds multiplied by the playback rate
- player.currentTime(
- player.currentTime() - 10 * player.playbackRate(),
- );
- event.stopPropagation();
- break;
- case 'KeyL': // 'L' key for seeking forward 10 seconds multiplied by the playback rate
- player.currentTime(
- player.currentTime() + 10 * player.playbackRate(),
- );
- event.stopPropagation();
- break;
- case 'KeyC':
- for (let i = 0; i < tracks.length; i++) {
- const track = tracks[i];
+ break;
+ case 'KeyF': // F key for fullscreen
+ if (player.isFullscreen_) document.exitFullscreen();
+ else player.requestFullscreen();
+ event.stopPropagation();
+ break;
+ case 'KeyR': // 'R' key to restart playback from the beginning
+ player.currentTime(0);
+ event.stopPropagation();
+ break;
+ case 'KeyM': // 'M' key to toggle mute/unmute
+ if (player.volume() === 0) {
+ player.volume(1);
+ } else {
+ player.volume(0);
+ }
+ event.stopPropagation();
+ break;
+ case 'KeyK': // 'K' key for play/pause toggle
+ if (player.paused()) {
+ player.play();
+ } else {
+ player.pause();
+ }
+ event.stopPropagation();
+ break;
+ case 'KeyJ': // 'J' key for seeking backward 10 seconds multiplied by the playback rate
+ player.currentTime(
+ player.currentTime() - 10 * player.playbackRate(),
+ );
+ event.stopPropagation();
+ break;
+ case 'KeyL': // 'L' key for seeking forward 10 seconds multiplied by the playback rate
+ player.currentTime(
+ player.currentTime() + 10 * player.playbackRate(),
+ );
+ event.stopPropagation();
+ break;
+ case 'KeyC':
+ for (let i = 0; i < tracks.length; i++) {
+ const track = tracks[i];
- if (track.kind === 'subtitles' && track.language === 'en') {
- if (track.mode === 'hidden') {
- track.mode = 'showing';
- } else {
- track.mode = 'hidden';
+ if (track.kind === 'subtitles' && track.language === 'en') {
+ if (track.mode === 'hidden') {
+ track.mode = 'showing';
+ } else {
+ track.mode = 'hidden';
+ }
}
}
- }
- break;
+ break;
}
}
};
@@ -357,6 +359,16 @@ export const VideoPlayer: FunctionComponent = ({
player.currentTime(parseInt(t, 10));
}
}, [searchParams, player]);
+
+ const isYoutubeUrl = (url: string) => {
+ const regex = /^https:\/\/www\.youtube\.com\/embed\/[a-zA-Z0-9_-]+/;
+ return regex.test(url);
+ };
+
+ if (isYoutubeUrl(vidUrl)) {
+ return ;
+ }
+
return (
= ({
};
return (
-
+
(
@@ -23,6 +24,7 @@ const WatchHistoryClient = ({ history }: { history: TWatchHistory[] }) => (
))}
+
);
diff --git a/src/components/YoutubeRenderer.tsx b/src/components/YoutubeRenderer.tsx
new file mode 100644
index 000000000..cd0d38532
--- /dev/null
+++ b/src/components/YoutubeRenderer.tsx
@@ -0,0 +1,23 @@
+import { FunctionComponent } from 'react';
+
+interface YoutubeRendererProps {
+ url: string;
+}
+
+export const YoutubeRenderer: FunctionComponent
= ({
+ url,
+}) => {
+ return (
+
+
+
+ );
+};
diff --git a/src/components/admin/ContentRendererClient.tsx b/src/components/admin/ContentRendererClient.tsx
index d864a5f3a..46344a3f7 100644
--- a/src/components/admin/ContentRendererClient.tsx
+++ b/src/components/admin/ContentRendererClient.tsx
@@ -118,7 +118,6 @@ export const ContentRendererClient = ({
setContentCompleted(true);
}}
/>
-
@@ -136,7 +135,6 @@ export const ContentRendererClient = ({
{/*
*/}
-
{metadata.slides ? (
0 && (
{
scrollTo({ top: 0, behavior: 'smooth' });
toggleShowChapters();
diff --git a/src/components/bookmark/BookmarkView.tsx b/src/components/bookmark/BookmarkView.tsx
index bed0c839d..9817d18b9 100644
--- a/src/components/bookmark/BookmarkView.tsx
+++ b/src/components/bookmark/BookmarkView.tsx
@@ -1,30 +1,23 @@
-import { Folder } from '@/db/course';
import BookmarkList from './BookmarkList';
import { TBookmarkWithContent } from '@/actions/bookmark/types';
-import { Sidebar } from '../Sidebar';
const BookmarkView = ({
- courseId,
- fullCourseContent,
bookmarkData,
}: {
- fullCourseContent: Folder[];
- courseId: string;
bookmarkData: TBookmarkWithContent[] | null | { error: string };
}) => {
return (
-
{bookmarkData === null ||
'error' in bookmarkData ||
!bookmarkData.length ? (
-
-
No bookmark added yet!
-
- ) : (
-
- )}
+
+
No bookmark added yet!
+
+ ) : (
+
+ )}
);
diff --git a/src/components/comment/CommentDeleteForm.tsx b/src/components/comment/CommentDeleteForm.tsx
index b7a5bc3df..7350312ed 100644
--- a/src/components/comment/CommentDeleteForm.tsx
+++ b/src/components/comment/CommentDeleteForm.tsx
@@ -29,7 +29,7 @@ const CommentDeleteForm = ({ commentId }: { commentId: number }) => {
return (