import React, { useState } from 'react' import UserAvatar from '../../UserAvatar' import { getUserAvatarMediaDirectory } from '@services/media/media' import { useMediaQuery } from 'usehooks-ts' import { Rss, PencilLine, TentTree } from 'lucide-react' import { useCourse } from '@components/Contexts/CourseContext' import { useLHSession } from '@components/Contexts/LHSessionContext' import useSWR, { mutate } from 'swr' import { getAPIUrl } from '@services/config/config' import { swrFetcher } from '@services/utils/ts/requests' import useAdminStatus from '@components/Hooks/useAdminStatus' import { useOrg } from '@components/Contexts/OrgContext' import { createCourseUpdate, deleteCourseUpdate } from '@services/courses/updates' import toast from 'react-hot-toast' import ConfirmationModal from '@components/Objects/StyledElements/ConfirmationModal/ConfirmationModal' import dayjs from 'dayjs' import relativeTime from 'dayjs/plugin/relativeTime' import * as Form from '@radix-ui/react-form' import FormLayout, { FormField, FormLabelAndMessage, Input, Textarea, } from '@components/Objects/StyledElements/Form/Form' import { useFormik } from 'formik' import { motion } from 'framer-motion' dayjs.extend(relativeTime) interface Author { user: { id: string 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 CourseAuthorsProps { authors: Author[] } 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 & Updates
{/* 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 UpdatesSection = () => { const [selectedView, setSelectedView] = React.useState('list') const adminStatus = useAdminStatus() const course = useCourse() as any const session = useLHSession() as any const access_token = session?.data?.tokens?.access_token const { data: updates } = useSWR( `${getAPIUrl()}courses/${course?.courseStructure.course_uuid}/updates`, (url) => swrFetcher(url, access_token) ) return (
Course Updates
{updates && updates.length > 0 && ( {updates.length} {updates.length === 1 ? 'update' : 'updates'} )}
{adminStatus.isAdmin && ( )}
{selectedView === 'list' ? ( ) : ( )}
) } const NewUpdateForm = ({ setSelectedView }: { setSelectedView: (view: string) => void }) => { const org = useOrg() as any const course = useCourse() as any const session = useLHSession() as any const formik = useFormik({ initialValues: { title: '', content: '' }, validate: (values) => { const errors: any = {} if (!values.title) errors.title = 'Title is required' if (!values.content) errors.content = 'Content is required' return errors }, onSubmit: async (values) => { const body = { title: values.title, content: values.content, course_uuid: course.courseStructure.course_uuid, org_id: org.id } const res = await createCourseUpdate(body, session.data?.tokens?.access_token) if (res.status === 200) { toast.success('Update added successfully') setSelectedView('list') mutate(`${getAPIUrl()}courses/${course?.courseStructure.course_uuid}/updates`) } else { toast.error('Failed to add update') } } }) return (