- {courseContent.map((content) => {
+ {filteredCourseContent.map((content) => {
const videoProgressPercent =
content.type === 'video' &&
content.videoFullDuration &&
diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx
index d113df33b..86a7881a8 100644
--- a/src/components/Sidebar.tsx
+++ b/src/components/Sidebar.tsx
@@ -9,7 +9,7 @@ import {
} from '@/components/ui/accordion';
import { Play, File, X, Menu } from 'lucide-react';
import { FullCourseContent } from '@/db/course';
-import { useRecoilState } from 'recoil';
+import { useRecoilState, useRecoilValue } from 'recoil';
import { sidebarOpen as sidebarOpenAtom } from '@/store/atoms/sidebar';
import { useEffect, useState, useCallback, useMemo } from 'react';
import { handleMarkAsCompleted } from '@/lib/utils';
@@ -17,7 +17,8 @@ import BookmarkButton from './bookmark/BookmarkButton';
import Link from 'next/link';
import { Button } from './ui/button';
import { AnimatePresence, motion } from 'framer-motion';
-
+import { FilterContent } from './FilterContent';
+import { selectFilter } from '@/store/atoms/filterContent';
const sidebarVariants = {
open: {
width: '100%',
@@ -47,7 +48,9 @@ export function Sidebar({
>([]);
const sidebarRef = useRef
(null);
const buttonRef = useRef(null);
+ const filterRef = useRef(null);
const closeSidebar = () => setSidebarOpen(false);
+ const currentfilter = useRecoilValue(selectFilter);
const findPathToContent = useCallback(
(
@@ -77,7 +80,8 @@ export function Sidebar({
if (
sidebarRef.current &&
!sidebarRef.current.contains(event.target as Node) &&
- !buttonRef.current?.contains(event.target as Node)
+ !buttonRef.current?.contains(event.target as Node) &&
+ !filterRef.current?.contains(event.target as Node)
) {
closeSidebar();
}
@@ -133,7 +137,6 @@ export function Sidebar({
(contents: FullCourseContent[]) => {
return contents.map((content) => {
const isActiveContent = currentActiveContentIds?.includes(content.id);
-
if (content.children && content.children.length > 0) {
return (
-
-
-
-
- {content.type === 'video' &&
}
- {content.type === 'notion' &&
}
+ (content.type === 'notion' ||
+ filterContent(currentfilter, content)) && (
+
+
+
+
+
+ {content.type === 'video' &&
}
+ {content.type === 'notion' &&
}
+
+
{content.title}
-
{content.title}
+ {content.type === 'video' && (
+
+ )}
- {content.type === 'video' && (
-
- )}
-
-
+
+ )
);
});
},
- [currentActiveContentIds, navigateToContent],
+ [currentActiveContentIds, navigateToContent, currentfilter],
);
const memoizedContent = useMemo(
@@ -206,9 +212,15 @@ export function Sidebar({
variants={sidebarVariants}
className="fixed right-0 top-0 z-[99999] flex h-screen w-full flex-col gap-4 overflow-y-auto rounded-r-lg border-l border-primary/10 bg-neutral-50 dark:bg-neutral-900 md:max-w-[30vw]"
>
-
+
+ {' '}
+
Course Content
+
);
}
+
+function filterContent(filter: string, content: FullCourseContent) {
+ if (filter === 'all' || filter === '') {
+ return true;
+ }
+ if (filter === 'watched') {
+ return content.videoProgress?.markAsCompleted;
+ }
+ if (filter === 'watching') {
+ return (
+ content.videoProgress?.markAsCompleted === false &&
+ content.videoProgress?.duration !== null &&
+ content.videoProgress?.duration !== 0
+ );
+ }
+ if (filter === 'unwatched') {
+ return (
+ content.videoProgress?.markAsCompleted === false &&
+ content.videoProgress?.duration === 0
+ );
+ }
+}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 20036a9f7..a9caec626 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -3,7 +3,7 @@ import { CommentType, Prisma } from '@prisma/client';
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
import Player from 'video.js/dist/types/player';
-
+import { Bookmark } from '@prisma/client';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
@@ -367,4 +367,47 @@ export const getDisabledFeature = (feature: string): boolean => {
.includes(feature);
};
-export type CourseContentType = 'folder' | 'video' | 'notion'
\ No newline at end of file
+export type CourseContentType = 'folder' | 'video' | 'notion';
+
+export type courseContent = {
+ type: CourseContentType;
+ title: string;
+ image: string;
+ id: number;
+ markAsCompleted: boolean;
+ percentComplete: number | null;
+ videoFullDuration?: number;
+ duration?: number;
+ bookmark: Bookmark | null;
+ weeklyContentTitles?: string[];
+};
+
+export function getFilteredContent(
+ courseContent: courseContent[],
+ filter: string,
+): courseContent[] {
+ if (filter === 'all' || filter === '' || courseContent[0]?.type === 'folder')
+ //Hoping no folder has recursive folders
+ return courseContent;
+
+ if (filter === 'watched')
+ return courseContent?.filter(
+ (content) => content?.markAsCompleted === true,
+ );
+
+ if (filter === 'watching')
+ return courseContent?.filter(
+ (content) =>
+ content?.markAsCompleted === false &&
+ content?.duration !== null &&
+ content?.duration !== 0,
+ );
+
+ if (filter === 'unwatched')
+ return courseContent?.filter(
+ (content) =>
+ content?.markAsCompleted === false && content?.duration === 0,
+ );
+
+ return [];
+}
diff --git a/src/store/atoms/filterContent.ts b/src/store/atoms/filterContent.ts
new file mode 100644
index 000000000..2e5bfff9d
--- /dev/null
+++ b/src/store/atoms/filterContent.ts
@@ -0,0 +1,6 @@
+import { atom } from 'recoil';
+
+export const selectFilter = atom({
+ key: 'selectFilter',
+ default: '',
+});