Skip to content

Commit

Permalink
Merge branch 'main' into feat/user-progress
Browse files Browse the repository at this point in the history
  • Loading branch information
hkirat authored Feb 4, 2024
2 parents 5c9404a + 72516ac commit f8082e6
Show file tree
Hide file tree
Showing 17 changed files with 1,270 additions and 725 deletions.
2 changes: 2 additions & 0 deletions prisma/migrations/20240203231627_hidden/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Content" ADD COLUMN "hidden" BOOLEAN NOT NULL DEFAULT false;
1 change: 1 addition & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ model Content {
id Int @id @default(autoincrement())
type String @default("folder")
title String
hidden Boolean @default(false)
description String?
thumbnail String?
parentId Int?
Expand Down
43 changes: 43 additions & 0 deletions src/app/api/admin/content/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const POST = async (req: NextRequest) => {
title,
courseId,
parentContentId,
metadata,
adminPassword,
}: {
type: 'video' | 'folder' | 'notion'
Expand Down Expand Up @@ -42,6 +43,12 @@ export const POST = async (req: NextRequest) => {
});
}
} else if (type === 'notion') {
await db.notionMetadata.create({
data: {
notionId: metadata.notionId,
contentId: content.id,
},
});
if (courseId && !parentContentId) {
await db.courseContent.create({
data: {
Expand All @@ -51,6 +58,42 @@ export const POST = async (req: NextRequest) => {
});
}
} else if (type === 'video') {
await db.videoMetadata.create({
data: {
video_360p_1: metadata.video_360p_1,
video_360p_2: metadata.video_360p_2,
video_360p_3: metadata.video_360p_3,
video_360p_4: metadata.video_360p_4,
video_720p_1: metadata.video_720p_1,
video_720p_2: metadata.video_720p_2,
video_720p_3: metadata.video_720p_3,
video_720p_4: metadata.video_720p_4,
video_1080p_1: metadata.video_1080p_1,
video_1080p_2: metadata.video_1080p_2,
video_1080p_3: metadata.video_1080p_3,
video_1080p_4: metadata.video_1080p_4,
/// mp4s

video_1080p_mp4_1: metadata.video_1080p_mp4_1,
video_1080p_mp4_2: metadata.video_1080p_mp4_2,
video_1080p_mp4_3: metadata.video_1080p_mp4_3,
video_1080p_mp4_4: metadata.video_1080p_mp4_4,
video_720p_mp4_1: metadata.video_720p_mp4_1,
video_720p_mp4_2: metadata.video_720p_mp4_2,
video_720p_mp4_3: metadata.video_720p_mp4_3,
video_720p_mp4_4: metadata.video_720p_mp4_4,
video_360p_mp4_1: metadata.video_360p_mp4_1,
video_360p_mp4_2: metadata.video_360p_mp4_2,
video_360p_mp4_3: metadata.video_360p_mp4_3,
video_360p_mp4_4: metadata.video_360p_mp4_4,

subtitles: metadata.subtitles || '',
segments: metadata.segments || [],
duration: metadata.duration,
thumbnail_mosiac_url: metadata.thumbnail_mosiac_url,
contentId: content.id,
},
});
if (courseId && !parentContentId) {
await db.courseContent.create({
data: {
Expand Down
31 changes: 27 additions & 4 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { MyCourses } from '@/components/MyCourses';
import LandingPage from '@/components/landing/landing-page';
import { authOptions } from '@/lib/auth';
import { cn } from '@/lib/utils';
import { getServerSession } from 'next-auth';
import { Poppins } from 'next/font/google';

const rs = Poppins({
weight: ['100', '200', '300', '400', '500', '600', '700', '800', '900'],
subsets: ['latin'],
});

const getUserDetails = async () => {
const session = await getServerSession(authOptions);
Expand All @@ -13,12 +20,28 @@ export default async function Home() {

if (session?.user) {
return (
<main className="max-w-screen-xl flex-col flex text-lg mx-auto">
<div className="text-2xl">Your courses</div>
<main className="max-w-screen-xl flex-col flex text-lg mx-auto pt-10 pb-6">
<div className="px-6 max-w-2xl antialiased">
<h1
className={cn(
'text-2xl font-semibold text-neutral-800 dark:text-neutral-200 md:text-3xl mb-2',
rs.className,
)}
>
Courses
</h1>
<p
className={cn(
'font-medium md:text-lg text-neutral-600 dark:text-neutral-300',
rs.className,
)}
>
List of purchased courses, click on any of them to navigate through
curriculum, access course material, watch lectures and much more.
</p>
</div>

<MyCourses />

<br />
</main>
);
}
Expand Down
157 changes: 157 additions & 0 deletions src/components/3dcard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
'use client';

import { cn } from '@/lib/utils';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import Image from 'next/image';
import React, {
createContext,
useState,
useContext,
useRef,
useEffect,
} from 'react';

const MouseEnterContext = createContext<
[boolean, React.Dispatch<React.SetStateAction<boolean>>] | undefined
>(undefined);

export const CardContainer = ({
children,
className,
containerClassName,
}: {
children?: React.ReactNode
className?: string
containerClassName?: string
}) => {
const containerRef = useRef<HTMLDivElement>(null);
const [isMouseEntered, setIsMouseEntered] = useState(false);

const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
if (!containerRef.current) return;
const { left, top, width, height } =
containerRef.current.getBoundingClientRect();
const x = (e.clientX - left - width / 2) / 25;
const y = (e.clientY - top - height / 2) / 25;
containerRef.current.style.transform = `rotateY(${x}deg) rotateX(${y}deg)`;
};

const handleMouseEnter = (e: React.MouseEvent<HTMLDivElement>) => {
setIsMouseEntered(true);
if (!containerRef.current) return;
};

const handleMouseLeave = (e: React.MouseEvent<HTMLDivElement>) => {
if (!containerRef.current) return;
setIsMouseEntered(false);
containerRef.current.style.transform = 'rotateY(0deg) rotateX(0deg)';
};
return (
<MouseEnterContext.Provider value={[isMouseEntered, setIsMouseEntered]}>
<div
className={cn(
'py-20 flex items-center justify-center',
containerClassName,
)}
style={{
perspective: '1000px',
}}
>
<div
ref={containerRef}
onMouseEnter={handleMouseEnter}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
className={cn(
'flex items-center justify-center relative transition-all duration-200 ease-linear',
className,
)}
style={{
transformStyle: 'preserve-3d',
}}
>
{children}
</div>
</div>
</MouseEnterContext.Provider>
);
};

export const CardBody = ({
children,
className,
}: {
children: React.ReactNode
className?: string
}) => {
return (
<div
className={cn(
'h-96 w-96 [transform-style:preserve-3d] [&>*]:[transform-style:preserve-3d]',
className,
)}
>
{children}
</div>
);
};

export const CardItem = ({
as: Tag = 'div',
children,
className,
translateX = 0,
translateY = 0,
translateZ = 0,
rotateX = 0,
rotateY = 0,
rotateZ = 0,
...rest
}: {
as?: React.ElementType
children: React.ReactNode
className?: string
translateX?: number | string
translateY?: number | string
translateZ?: number | string
rotateX?: number | string
rotateY?: number | string
rotateZ?: number | string
}) => {
const ref = useRef<HTMLDivElement>(null);
const [isMouseEntered] = useMouseEnter();

useEffect(() => {
handleAnimations();
}, [isMouseEntered]);

const handleAnimations = () => {
if (!ref.current) return;
if (isMouseEntered) {
ref.current.style.transform = `translateX(${translateX}px) translateY(${translateY}px) translateZ(${translateZ}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) rotateZ(${rotateZ}deg)`;
} else {
ref.current.style.transform =
'translateX(0px) translateY(0px) translateZ(0px) rotateX(0deg) rotateY(0deg) rotateZ(0deg)';
}
};

return (
<Tag
ref={ref}
className={cn('w-fit transition duration-200 ease-linear', className)}
{...rest}
>
{children}
</Tag>
);
};

// Create a hook to use the context
export const useMouseEnter = () => {
const context = useContext(MouseEnterContext);
if (context === undefined) {
throw new Error('useMouseEnter must be used within a MouseEnterProvider');
}
return context;
};
3 changes: 2 additions & 1 deletion src/components/Appbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ export const Appbar = () => {
href={'https://harkirat.classx.co.in/new-courses'}
target="_blank"
>
Join now <Sparkles className="ml-1 h-4 w-4" />
<p className="text-white">Join now</p>{' '}
<Sparkles className="text-white ml-2 h-4 w-4 hover:translate-x-0.5 ease-linear duration-200" />
</Link>
</Button>
</div>
Expand Down
46 changes: 29 additions & 17 deletions src/components/CourseCard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use client';
import { Course } from '@/store/atoms';
import PercentageComplete from './PercentageComplete';
import { Button } from './ui/button';
import { ChevronRight } from 'lucide-react';

export const CourseCard = ({
course,
Expand All @@ -11,7 +13,7 @@ export const CourseCard = ({
}) => {
return (
<div
className="max-w-sm bg-white border border-gray-200 rounded-lg shadow dark:bg-gray-800 dark:border-gray-700"
className="max-w-full flex flex-col md:flex-row items-center bg-slate-100 md:border rounded-lg shadow-lg dark:bg-gradient-to-t md:dark:bg-gradient-to-l dark:from-slate-900 dark:to-slate-800"
onClick={() => {
onClick();
}}
Expand All @@ -28,16 +30,31 @@ export const CourseCard = ({
<img src={course.imageUrl} alt={course.title} className="rounded-md" />
</div>
<div className="p-2">
<div className="flex justify-between">
<div className="mt-4 mb-2">{course.title} Cohort</div>
</div>
<div>
<button
type="button"
className="text-white bg-blue-700 hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300 font-medium rounded-full text-sm px-5 py-2.5 text-center me-2 mb-2 w-full"
>
View Content
</button>
<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-6 py-2 w-full h-full">
<div className="flex flex-col w-full h-full items-start justify-between md:py-4">
<div className="w-full items-start mb-3">
<h2 className="mb-0 md:mb-2 dark:text-neutral-100 text-neutral-800 text-xl sm:text-3xl font-semibold">
{course.title} Cohort
</h2>

<p className="dark:text-neutral-200 text-neutral-700 font-medium">
{course.description}
</p>
</div>

<div className="w-full flex justify-end pb-2 md:pb-0">
<Button className="group">
Explore Content{' '}
<ChevronRight className="h-4 w-4 ml-1 group-hover:translate-x-1 transition" />
</Button>
</div>
</div>
</div>
</div>
Expand All @@ -47,12 +64,7 @@ export const CourseCard = ({
export const CourseSkeleton = () => {
return (
<div className="animate-pulse">
<div className="rounded-md bg-gray-400 h-56"></div>
<div className="flex-1 space-y-4 py-2">
<div className="space-y-6">
<div className="h-4 bg-gray-400 rounded w-4/6"></div>
</div>
</div>
<div className="rounded-md bg-slate-50 dark:bg-slate-900 h-64"></div>
</div>
);
};
2 changes: 1 addition & 1 deletion src/components/Courses.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useRouter } from 'next/navigation';
export const Courses = ({ courses }: { courses: Course[] }) => {
const router = useRouter();
return (
<div className="max-w-screen-xl justify-between mx-auto p-4 cursor-pointer grid grid-cols-1 gap-5 md:grid-cols-3">
<div className="max-w-screen-xl w-full mx-auto py-6 px-6 cursor-pointer grid grid-rows-1 gap-5 md:grid-rows-3">
{courses?.map((course) => (
<CourseCard
key={course.id}
Expand Down
Loading

0 comments on commit f8082e6

Please sign in to comment.