Skip to content

Commit

Permalink
Merge branch 'main' into fix/landing-and-card
Browse files Browse the repository at this point in the history
  • Loading branch information
tanayvaswani authored Feb 4, 2024
2 parents b80bde6 + 38c9bb9 commit ac48779
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 22 deletions.
2 changes: 2 additions & 0 deletions src/components/CourseCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ export const CourseCard = ({
onClick();
}}
>

<div className="p-2">
<img
src={course.imageUrl}
alt={course.title}
className="rounded-t-md md:rounded-l-md md:rounded-r-none md:max-w-md"
/>

</div>

<div className="px-4 md:px-6 py-2 w-full h-full">
Expand Down
6 changes: 2 additions & 4 deletions src/components/CourseView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ export const CourseView = ({
type: contentType || 'video',
description: courseContent[0]?.description || '',
markAsCompleted:
courseContent[0]?.videoProgress[0]?.markAsCompleted ||
false,
courseContent[0]?.videoProgress?.markAsCompleted || false,
}}
/>
) : null}
Expand All @@ -51,8 +50,7 @@ export const CourseView = ({
title: x?.title || '',
image: x?.thumbnail || '',
id: x?.id || 0,
markAsCompleted:
x?.videoProgress[0]?.markAsCompleted || false,
markAsCompleted: x?.videoProgress?.markAsCompleted || false,
percentComplete: getFolderPercentCompleted(x?.children),
}))}
courseId={parseInt(course.id, 10)}
Expand Down
93 changes: 84 additions & 9 deletions src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import { Button } from './ui/button';
import { BackArrow } from '@/icons/BackArrow';
import { useRecoilState } from 'recoil';
import { sidebarOpen as sidebarOpenAtom } from '@/store/atoms/sidebar';
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import { handleMarkAsCompleted } from '@/lib/utils';

export function Sidebar({
courseId,
Expand Down Expand Up @@ -65,10 +66,12 @@ export function Sidebar({
<AccordionItem
key={content.id}
value={`item-${content.id}`}
className="text-gray-900 dark:text-white"
className="text-gray-900 dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 cursor-pointer"
>
<AccordionTrigger>{content.title}</AccordionTrigger>
<AccordionContent>
<AccordionTrigger className="px-2">
{content.title}
</AccordionTrigger>
<AccordionContent className="p-0 m-0">
{/* Render the children of this folder */}
{renderContent(content.children)}
</AccordionContent>
Expand All @@ -79,12 +82,25 @@ export function Sidebar({
return (
<div
key={content.id}
className="p-2"
className="p-2 flex border-gray-300 border-b hover:bg-gray-100 dark:hover:bg-gray-700 dark:border-gray-700 cursor-pointer bg-gray-50 dark:bg-gray-800"
onClick={() => {
navigateToContent(content.id);
}}
>
{content.title}
<div className="flex justify-between w-full">
<div className="flex">
<div className="pr-2">
{content.type === 'video' ? <VideoIcon /> : null}
{content.type === 'notion' ? <NotionIcon /> : null}
</div>
<div>{content.title}</div>
</div>
{content.type === 'video' ? (
<div className="flex flex-col justify-center ml-2">
<Check content={content} />
</div>
) : null}
</div>
</div>
);
});
Expand All @@ -95,8 +111,8 @@ export function Sidebar({
}

return (
<div className="w-64">
<div className="px-3 py-4 overflow-y-auto bg-gray-50 dark:bg-gray-800 cursor-pointer w-full sticky top-[64px] self-start">
<div className="w-84" style={{ width: '300px' }}>
<div className="overflow-scroll min-h-screen overflow-y-auto bg-gray-50 dark:bg-gray-800 cursor-pointer w-full sticky top-[64px] self-start w-84">
<div className="flex">
{/* <ToggleButton
onClick={() => {
Expand Down Expand Up @@ -166,11 +182,70 @@ function GoBackButton() {
};

return (
<div className="w-full">
<div className="w-full p-2">
{/* Your component content */}
<Button size={'full'} onClick={goBack}>
<BackArrow /> <div className="pl-4">Go Back</div>
</Button>
</div>
);
}

function VideoIcon() {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
className="w-6 h-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m15.75 10.5 4.72-4.72a.75.75 0 0 1 1.28.53v11.38a.75.75 0 0 1-1.28.53l-4.72-4.72M4.5 18.75h9a2.25 2.25 0 0 0 2.25-2.25v-9a2.25 2.25 0 0 0-2.25-2.25h-9A2.25 2.25 0 0 0 2.25 7.5v9a2.25 2.25 0 0 0 2.25 2.25Z"
/>
</svg>
);
}

function NotionIcon() {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
className="w-6 h-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"
/>
</svg>
);
}

// Todo: Fix types here
function Check({ content }: { content: any }) {
const [completed, setCompleted] = useState(
content?.videoProgress?.markAsCompleted || false,
);
return (
<>
<input
defaultChecked={completed}
onClick={async (e) => {
setCompleted(!completed);
handleMarkAsCompleted(!completed, content.id);
e.stopPropagation();
}}
type="checkbox"
className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
/>
</>
);
}
62 changes: 54 additions & 8 deletions src/db/course.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import db from '@/db';
import { Cache } from '@/db/Cache';
import { authOptions } from '@/lib/auth';
import { getServerSession } from 'next-auth';

export interface Content {
id: number
Expand All @@ -10,6 +12,10 @@ export interface Content {
parentId: number | null
createdAt: string
children: Content[]
videoProgress?: {
currentTimestamp: string
markAsCompleted?: boolean
}
}

export interface Folder extends Content {
Expand Down Expand Up @@ -82,8 +88,8 @@ async function getAllContent() {
return value;
}
const allContent = await db.content.findMany({
include: {
videoProgress: true,
where: {
hidden: false,
},
});

Expand All @@ -92,15 +98,13 @@ async function getAllContent() {
return allContent;
}

export const getFullCourseContent = async (courseId: number) => {
const value = Cache.getInstance().get('getFullCourseContent', [
async function getRootCourseContent(courseId: number) {
const value = Cache.getInstance().get('getRootCourseContent', [
courseId.toString(),
]);
if (value) {
return value;
}

const contents = await getAllContent();
const courseContent = await db.courseContent.findMany({
orderBy: [
{
Expand All @@ -112,9 +116,51 @@ export const getFullCourseContent = async (courseId: number) => {
},
include: { content: true },
});
Cache.getInstance().set(
'getRootCourseContent',
[courseId.toString()],
courseContent,
);
return courseContent;
}

function getVideoProgressForUser(userId: string) {
return db.videoProgress.findMany({
where: {
userId,
},
});
}

export const getFullCourseContent = async (courseId: number) => {
// const value = Cache.getInstance().get('getFullCourseContent', [
// courseId.toString(),
// ]);
// if (value) {
// return value;
// }
const session = await getServerSession(authOptions);
const contents = await getAllContent();
const courseContent = await getRootCourseContent(courseId);
const videoProgress = await getVideoProgressForUser(session?.user?.id);
const contentMap = new Map<string, any>(
contents.map((content: any) => [content.id, { ...content, children: [] }]),
contents.map((content: any) => [
content.id,
{
...content,
children: [],
videoProgress:
content.type === 'video'
? {
duration: videoProgress.find((x) => x.contentId === content.id)
?.currentTimestamp,
markAsCompleted: videoProgress.find(
(x) => x.contentId === content.id,
)?.markAsCompleted,
}
: null,
},
]),
);
const rootContents: any[] = [];
contents
Expand All @@ -124,7 +170,7 @@ export const getFullCourseContent = async (courseId: number) => {
contentMap
.get(content.parentId)
.children.push(contentMap.get(content.id));
} else if (courseContent.find((x) => x.contentId === content.id)) {
} else if (courseContent.find((x: any) => x.contentId === content.id)) {
rootContents.push(contentMap.get(content.id));
}
});
Expand Down
2 changes: 1 addition & 1 deletion src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ export const getFolderPercentCompleted = (childrenContent: any) => {
);
const totalVideosWatched = videos.filter(
({ videoProgress }: any) =>
videoProgress && videoProgress[0]?.markAsCompleted,
videoProgress && videoProgress?.markAsCompleted,
).length;
return Math.ceil((totalVideosWatched / videos.length) * 100);
}
Expand Down

0 comments on commit ac48779

Please sign in to comment.