import React, { useState, useEffect } from 'react' import UserAvatar from '../../UserAvatar' import { getUserAvatarMediaDirectory } from '@services/media/media' 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 { useMediaQuery } from 'usehooks-ts' import { getUriWithOrg, getUriWithoutOrg } from '@services/config/config' import { getProductsByCourse } from '@services/payments/products' import { LogIn, LogOut, ShoppingCart, AlertCircle } from 'lucide-react' import Modal from '@components/Objects/StyledElements/Modal/Modal' import CoursePaidOptions from './CoursePaidOptions' import { checkPaidAccess } from '@services/payments/payments' interface Author { user: { user_uuid: string avatar_image: string first_name: string last_name: string username: string } authorship: 'CREATOR' | 'CONTRIBUTOR' | 'MAINTAINER' | 'REPORTER' authorship_status: 'ACTIVE' | 'INACTIVE' | 'PENDING' } interface CourseRun { status: string course_id: string } interface Course { id: string authors: Author[] trail?: { runs: CourseRun[] } chapters?: Array<{ name: string activities: Array<{ activity_uuid: string name: string activity_type: string }> }> } interface CourseActionsProps { courseuuid: string orgslug: string course: Course & { org_id: number } } // Separate component for author display const AuthorInfo = ({ author, isMobile }: { author: Author, isMobile: boolean }) => (
Author
{(author.user.first_name && author.user.last_name) ? (

{`${author.user.first_name} ${author.user.last_name}`}

@{author.user.username}
) : (

@{author.user.username}

)}
) const MultipleAuthors = ({ authors, isMobile }: { authors: Author[], isMobile: boolean }) => { const displayedAvatars = authors.slice(0, 3) const displayedNames = authors.slice(0, 2) const remainingCount = Math.max(0, authors.length - 3) // Consistent sizes for both avatars and badge const avatarSize = isMobile ? 72 : 86 const borderSize = "border-4" return (
Authors
{/* Avatars row */}
{displayedAvatars.map((author, index) => (
))} {remainingCount > 0 && (
+{remainingCount}
)}
{/* Names row - improved display logic */}
{authors.length === 1 ? ( {authors[0].user.first_name && authors[0].user.last_name ? `${authors[0].user.first_name} ${authors[0].user.last_name}` : `@${authors[0].user.username}`} ) : ( <> {displayedNames.map((author, index) => ( {author.user.first_name && author.user.last_name ? `${author.user.first_name} ${author.user.last_name}` : `@${author.user.username}`} {index === 0 && authors.length > 1 && index < displayedNames.length - 1 && " & "} ))} {authors.length > 2 && ( & {authors.length - 2} more )} )}
{authors.length === 1 ? ( @{authors[0].user.username} ) : ( <> {displayedNames.map((author, index) => ( @{author.user.username} {index === 0 && authors.length > 1 && index < displayedNames.length - 1 && " & "} ))} )}
) } const Actions = ({ courseuuid, orgslug, course }: CourseActionsProps) => { const router = useRouter() const session = useLHSession() as any const [linkedProducts, setLinkedProducts] = useState([]) const [isLoading, setIsLoading] = useState(true) const [isActionLoading, setIsActionLoading] = useState(false) const [isModalOpen, setIsModalOpen] = useState(false) const [hasAccess, setHasAccess] = useState(null) const isStarted = course.trail?.runs?.some( (run) => run.status === 'STATUS_IN_PROGRESS' && run.course_id === course.id ) ?? 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') 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) try { if (isStarted) { await removeCourse('course_' + courseuuid, orgslug, session.data?.tokens?.access_token) await revalidateTags(['courses'], orgslug) router.refresh() } else { await startCourse('course_' + courseuuid, orgslug, session.data?.tokens?.access_token) await revalidateTags(['courses'], orgslug) // 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 { router.refresh() } } } catch (error) { console.error('Failed to perform course action:', error) } finally { setIsActionLoading(false) } } 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.

) : (

Paid Course

This course requires purchase to access its content.

)} {!hasAccess && ( <> } dialogTitle="Purchase Course" dialogDescription="Select a payment option to access this course" minWidth="sm" /> )}
) } return ( ) } function CoursesActions({ courseuuid, orgslug, course }: CourseActionsProps) { const router = useRouter() const session = useLHSession() as any const isMobile = useMediaQuery('(max-width: 768px)') // Filter active authors and sort by role priority const sortedAuthors = [...course.authors] .filter(author => author.authorship_status === 'ACTIVE') .sort((a, b) => { const rolePriority: Record = { 'CREATOR': 0, 'MAINTAINER': 1, 'CONTRIBUTOR': 2, 'REPORTER': 3 }; return rolePriority[a.authorship] - rolePriority[b.authorship]; }); return (
) } export default CoursesActions