11'use client' ;
22import { Course } from '@/store/atoms' ;
3- import PercentageComplete from './PercentageComplete' ;
43import { useRouter } from 'next/navigation' ;
54import Link from 'next/link' ;
65import { Button } from './ui/button' ;
6+ import { Card , CardContent } from "@/components/ui/card" ;
7+ import { motion } from "framer-motion" ;
8+ import { MessageCircle , PlayCircle } from "lucide-react" ;
79
810export const CourseCard = ( {
911 course,
@@ -14,54 +16,63 @@ export const CourseCard = ({
1416} ) => {
1517 const router = useRouter ( ) ;
1618 const imageUrl = course . imageUrl ? course . imageUrl : 'banner_placeholder.png' ;
19+ const percentage = course . totalVideos !== undefined ? Math . ceil ( ( ( course . totalVideosWatched ?? 0 ) / course ?. totalVideos ) * 100 ) : 0 ;
20+
1721 return (
18- < div
19- className = { `flex w-full cursor-pointer flex-col rounded-2xl bg-primary/5 transition-all duration-300 hover:-translate-y-2 hover:border-primary/20` }
20- onClick = { onClick }
21- >
22- < div className = "flex flex-col" >
22+ < Card className = "w-full max-w-sm overflow-hidden transition-all hover:shadow-lg cursor-pointer" onClick = { onClick } >
23+ < div className = "relative aspect-video overflow-hidden" >
2324 < img
2425 alt = { course . title }
25- className = "size-full rounded-t-2xl bg-cover"
26+ className = "object-cover w-full h-full transition-transform hover:scale-105"
27+ height = "200"
2628 src = { imageUrl }
29+ style = { {
30+ aspectRatio : "300/200" ,
31+ objectFit : "cover" ,
32+ filter : "brightness(1.2) contrast(1.1)" ,
33+ } }
34+ width = "300"
2735 />
2836
29- { course . totalVideos !== undefined && (
30- < >
31- < PercentageComplete
32- percent = { Math . ceil (
33- ( ( course . totalVideosWatched ?? 0 ) / course . totalVideos ) * 100 ,
34- ) }
35- />
36- </ >
37- ) }
38- </ div >
39- < div className = "flex flex-1 flex-col justify-between gap-4 p-4" >
40- < div className = "flex w-full justify-between gap-2" >
41- < h3 className = "w-full truncate text-xl font-bold capitalize tracking-tighter md:text-2xl" >
42- { course . title }
43- </ h3 >
44- { course . totalVideos !== undefined && (
45- < >
46- < span
47- className = { `text-lg font-bold tracking-tight text-primary/80` }
48- >
49- { Math . ceil (
50- ( ( course . totalVideosWatched ?? 0 ) / course . totalVideos ) * 100 ,
51- ) }
52- %
53- </ span >
54- </ >
55- ) }
37+ < div className = "absolute inset-0 bg-gradient-to-t from-black/60 to-transparent" />
38+ < div className = "absolute bottom-4 right-4 flex justify-between items-end" >
39+ < div className = "bg-white rounded-full p-1 shadow-md" >
40+ < div className = "relative w-12 h-12" >
41+ < svg className = "w-12 h-12 transform -rotate-90" viewBox = "0 0 100 100" >
42+ < circle className = "stroke-current text-gray-300" strokeWidth = "10" fill = "gray" r = "40" cx = "50" cy = "50" />
43+ < motion . circle
44+ className = "stroke-current text-black"
45+ strokeWidth = "10"
46+ strokeLinecap = "round"
47+ fill = "white"
48+ r = "40"
49+ cx = "50"
50+ cy = "50"
51+ initial = { { strokeDasharray : "0 251.2" } }
52+ animate = { { strokeDasharray : `${ percentage * 2.512 } 251.2` } }
53+ transition = { { duration : 1 , ease : "easeInOut" } }
54+ />
55+ </ svg >
56+ < div className = "absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 text-center" >
57+ < span className = "text-xs font-bold text-black dark:text-black flex justify-center" > { percentage } %</ span >
58+ </ div >
59+ </ div >
60+ </ div >
61+
5662 </ div >
57- < div className = "flex flex-col gap-2" >
58- < Button size = { 'lg' } variant = { 'branding' } onClick = { onClick } >
63+ </ div >
64+ < CardContent className = "p-4" >
65+ < h3 className = "text-lg font-semibold text-primary mb-2 line-clamp-2" >
66+ { course . title }
67+ </ h3 >
68+ < div className = "flex space-x-2" >
69+ < Button className = "flex-1" variant = "default" onClick = { onClick } >
70+ < PlayCircle className = "w-4 h-4 mr-2" />
5971 View Course
6072 </ Button >
61-
6273 { course . certIssued ? (
6374 < Button
64- variant = "link "
75+ variant = "outline "
6576 size = { 'lg' }
6677 onClick = { ( e ) => {
6778 e . stopPropagation ( ) ;
@@ -72,16 +83,17 @@ export const CourseCard = ({
7283 </ Button >
7384 ) : (
7485 < Link
75- className = "inline-flex items-center justify-center rounded-md py-2 text-sm font-medium text-primary underline-offset-4 ring-offset-background transition-colors hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
86+ className = "flex-1 inline-flex items-center justify-center rounded-md py-2 text-sm font-medium text-primary underline-offset-4 ring-offset-background transition-colors hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
7687 href = { course . discordOauthUrl }
7788 target = { 'blank' }
7889 >
90+ < MessageCircle className = "w-4 h-4 mr-2" />
7991 Join Discord
8092 </ Link >
8193 ) }
8294 </ div >
83- </ div >
84- </ div >
95+ </ CardContent >
96+ </ Card >
8597 ) ;
8698} ;
8799
0 commit comments