import React, { useState, useEffect } from 'react' import { removeCourse, startCourse } from '@services/courses/activity' import { revalidateTags } from '@services/utils/ts/requests' import { useRouter } from 'next/navigation' import { useLHSession } from '@components/Contexts/LHSessionContext' import { getAPIUrl, getUriWithOrg, getUriWithoutOrg } from '@services/config/config' import { getProductsByCourse } from '@services/payments/products' import { LogIn, LogOut, ShoppingCart, AlertCircle, UserPen, ClockIcon, ArrowRight, Sparkles, BookOpen } from 'lucide-react' import Modal from '@components/Objects/StyledElements/Modal/Modal' import CoursePaidOptions from './CoursePaidOptions' import { checkPaidAccess } from '@services/payments/payments' import { applyForContributor } from '@services/courses/courses' import toast from 'react-hot-toast' import { useContributorStatus } from '../../../../hooks/useContributorStatus' import CourseProgress from '../CourseProgress/CourseProgress' import UserAvatar from '@components/Objects/UserAvatar' import { useOrg } from '@components/Contexts/OrgContext' import { mutate } from 'swr' interface CourseRun { status: string course_id: string steps: Array<{ activity_id: string complete: boolean }> } interface Course { id: string course_uuid: string trail?: { runs: CourseRun[] } chapters?: Array<{ name: string activities: Array<{ activity_uuid: string name: string activity_type: string }> }> open_to_contributors?: boolean } interface CourseActionsProps { courseuuid: string orgslug: string course: Course & { org_id: number } trailData?: any } function CoursesActions({ courseuuid, orgslug, course, trailData }: CourseActionsProps) { const router = useRouter() const session = useLHSession() as any const [linkedProducts, setLinkedProducts] = useState([]) const [isLoading, setIsLoading] = useState(true) const [isActionLoading, setIsActionLoading] = useState(false) const [isContributeLoading, setIsContributeLoading] = useState(false) const [isModalOpen, setIsModalOpen] = useState(false) const [hasAccess, setHasAccess] = useState(null) const { contributorStatus, refetch } = useContributorStatus(courseuuid) const [isProgressOpen, setIsProgressOpen] = useState(false) const org = useOrg() as any // Clean up course UUID by removing 'course_' prefix if it exists const cleanCourseUuid = course.course_uuid?.replace('course_', ''); const isStarted = trailData?.runs?.find( (run: any) => { const cleanRunCourseUuid = run.course?.course_uuid?.replace('course_', ''); return cleanRunCourseUuid === cleanCourseUuid; } ) ?? false; useEffect(() => { const fetchLinkedProducts = async () => { try { const response = await getProductsByCourse( course.org_id, course.id, session.data?.tokens?.access_token ) setLinkedProducts(response.data || []) } catch (error) { console.error('Failed to fetch linked products') } finally { setIsLoading(false) } } fetchLinkedProducts() }, [course.id, course.org_id, session.data?.tokens?.access_token]) useEffect(() => { const checkAccess = async () => { if (!session.data?.user) return try { const response = await checkPaidAccess( parseInt(course.id), course.org_id, session.data?.tokens?.access_token ) setHasAccess(response.has_access) } catch (error) { console.error('Failed to check course access') toast.error('Failed to check course access. Please try again later.') setHasAccess(false) } } if (linkedProducts.length > 0) { checkAccess() } }, [course.id, course.org_id, session.data?.tokens?.access_token, linkedProducts]) const handleCourseAction = async () => { if (!session.data?.user) { router.push(getUriWithoutOrg(`/signup?orgslug=${orgslug}`)) return } setIsActionLoading(true) const loadingToast = toast.loading( isStarted ? 'Leaving course...' : 'Starting course...' ) try { if (isStarted) { await removeCourse('course_' + courseuuid, orgslug, session.data?.tokens?.access_token) mutate(`${getAPIUrl()}trail/org/${org?.id}/trail`) toast.success('Successfully left the course', { id: loadingToast }) } else { await startCourse('course_' + courseuuid, orgslug, session.data?.tokens?.access_token) mutate(`${getAPIUrl()}trail/org/${org?.id}/trail`) toast.success('Successfully started the course', { id: loadingToast }) // Get the first activity from the first chapter const firstChapter = course.chapters?.[0] const firstActivity = firstChapter?.activities?.[0] if (firstActivity) { // Redirect to the first activity router.push( getUriWithOrg(orgslug, '') + `/course/${courseuuid}/activity/${firstActivity.activity_uuid.replace('activity_', '')}` ) } else { mutate(`${getAPIUrl()}trail/org/${org?.id}/trail`) } } } catch (error) { console.error('Failed to perform course action:', error) toast.error( isStarted ? 'Failed to leave the course. Please try again later.' : 'Failed to start the course. Please try again later.', { id: loadingToast } ) } finally { setIsActionLoading(false) } } const handleApplyToContribute = async () => { if (!session.data?.user) { router.push(getUriWithoutOrg(`/signup?orgslug=${orgslug}`)) return } setIsContributeLoading(true) const loadingToast = toast.loading('Submitting contributor application...') try { const data = { message: "I would like to contribute to this course." } await applyForContributor('course_' + courseuuid, data, session.data?.tokens?.access_token) await revalidateTags(['courses'], orgslug) await refetch() toast.success('Your application to contribute has been submitted successfully', { id: loadingToast }) } catch (error) { console.error('Failed to apply as contributor:', error) toast.error('Failed to submit your application. Please try again later.', { id: loadingToast }) } finally { setIsContributeLoading(false) } } const renderActionButton = (action: 'start' | 'leave') => { if (!session.data?.user) { return ( <> {action === 'start' ? 'Start Course' : 'Leave Course'} ); } return ( <> {action === 'start' ? 'Start Course' : 'Leave Course'} ); }; const renderContributorButton = () => { if (contributorStatus === 'INACTIVE' || course.open_to_contributors !== true) { return null; } if (!session.data?.user) { return ( ); } if (contributorStatus === 'ACTIVE') { return (
You are a contributor
); } if (contributorStatus === 'PENDING') { return (
Contributor application pending
); } return ( ); }; const renderProgressSection = () => { const totalActivities = course.chapters?.reduce((acc: number, chapter: any) => acc + chapter.activities.length, 0) || 0; // Find the correct run using the cleaned UUID const run = trailData?.runs?.find( (run: any) => { const cleanRunCourseUuid = run.course?.course_uuid?.replace('course_', ''); return cleanRunCourseUuid === cleanCourseUuid; } ); const completedActivities = run?.steps?.filter((step: any) => step.complete)?.length || 0; const progressPercentage = Math.round((completedActivities / totalActivities) * 100); if (!isStarted) { return (
Ready to Begin?
Start your learning journey with {totalActivities} exciting {totalActivities === 1 ? 'activity' : 'activities'}
); } return (
{progressPercentage}%
); }; if (isLoading) { return
} if (linkedProducts.length > 0) { return (
{hasAccess ? ( <>

You Own This Course

You have purchased this course and have full access to all content.

{renderContributorButton()} ) : ( <>

Paid Course

This course requires purchase to access its content.

} dialogTitle="Purchase Course" dialogDescription="Select a payment option to access this course" minWidth="sm" /> {renderContributorButton()} )}
) } return (
{/* Progress Section */} {renderProgressSection()} {/* Start/Leave Course Button */} {/* Contributor Button */} {renderContributorButton()} {/* Course Progress Modal */} setIsProgressOpen(false)} trailData={trailData} />
) } export default CoursesActions