diff --git a/app/dashboard/courses/[courseId]/CourseDetailPageClient.jsx b/app/dashboard/courses/[courseId]/CourseDetailPageClient.jsx index 6068a0de..eaa48e0f 100644 --- a/app/dashboard/courses/[courseId]/CourseDetailPageClient.jsx +++ b/app/dashboard/courses/[courseId]/CourseDetailPageClient.jsx @@ -2,7 +2,7 @@ import VidPlayerBox from "@/components/atoms/dashboard/vid-player-box"; import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar"; import Link from "next/link"; -import React, { useState, useMemo } from "react"; +import React, { useState, useMemo, useCallback } from "react"; import Button from "@/components/atoms/form/Button"; import StarRate from "@/components/atoms/form/StarRate"; import ReviewsSection from "@/components/organisms/dashboard/ReviewsSection"; @@ -10,8 +10,10 @@ import { useAuth } from "@/hooks/useAuth"; import { Textarea } from "@/components/ui/textarea"; import { addCourseReview } from "@/lib/actions/courses/addReview"; import { useHasCourse, usePurchaseCourse } from "@/hooks/usePurchase"; +import { useCourseProgress, formatTime } from "@/hooks/useCourseProgress"; +import { Progress } from "@/components/ui/progress"; import { toast } from "sonner"; -import { Wallet } from "lucide-react"; +import { Wallet, RotateCcw, Play } from "lucide-react"; import PaymentModal from "@/components/stellar/PaymentModal"; import { useStellar } from "@/components/stellar/StellarProvider"; @@ -26,12 +28,45 @@ export default function CourseDetailClient({ course }) { const [loading, setLoading] = useState(false); const [showPaymentModal, setShowPaymentModal] = useState(false); - // Check if user already owns the course const hasCourse = useHasCourse(course?._id); - // Local state to hide button after purchase const [purchased, setPurchased] = useState(false); - // Check if the current user has already reviewed + const { + progress, + reportProgress, + resetProgress, + resumeTime, + resumeLabel, + } = useCourseProgress(course?._id); + + const [useResume, setUseResume] = useState(false); + const [playerKey, setPlayerKey] = useState(0); + + const effectiveStartTime = useResume && resumeTime ? resumeTime : 0; + + const handleTimeUpdate = useCallback( + (currentTime, duration) => { + reportProgress(currentTime, duration); + }, + [reportProgress] + ); + + const handleEnded = useCallback(() => { + if (course?._id) { + reportProgress(progress.durationSeconds || 0, progress.durationSeconds || 0); + } + }, [reportProgress, progress.durationSeconds, course?._id]); + + const handleResume = () => { + setUseResume(true); + }; + + const handleStartOver = () => { + resetProgress(); + setUseResume(false); + setPlayerKey((k) => k + 1); + }; + const userReview = useMemo(() => { if (!user?._id || !course?.reviews) return null; return course.reviews.find( @@ -39,10 +74,8 @@ export default function CourseDetailClient({ course }) { ); }, [user, course?.reviews]); - // Check if creator has wallet connected const creatorHasWallet = course?.createdBy?.stellarWallet?.publicKey; - // Handle opening the payment modal const handlePurchaseCourse = () => { if (!user?._id) { toast.error("Please sign in to purchase this course."); @@ -51,7 +84,6 @@ export default function CourseDetailClient({ course }) { setShowPaymentModal(true); }; - // Handle successful payment const handlePaymentSuccess = async (result) => { setPurchased(true); if (user?._id) { @@ -86,7 +118,6 @@ export default function CourseDetailClient({ course }) { return null; } - // Check if user can access the course const canAccess = hasCourse || purchased || user?._id === course.createdBy?._id; @@ -97,12 +128,77 @@ export default function CourseDetailClient({ course }) { {canAccess ? ( -
{resumeLabel}
+ +