diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx index 193ed281..cb265b42 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx @@ -274,7 +274,7 @@ function ActivityClient(props: ActivityClientProps) { for (let j = 0; j < chapter.activities.length; j++) { let activity = chapter.activities[j] if (activity.id === activity_id) { - return chapter.name + return `Chapter ${i + 1} : ${chapter.name}` } } } @@ -570,7 +570,7 @@ function ActivityClient(props: ActivityClientProps) {

- Chapter : {getChapterNameByActivityId(course, activity.id)} + {getChapterNameByActivityId(course, activity.id)}

{activity.name} diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/trail/trail.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/trail/trail.tsx index dbf3bb33..686da786 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/trail/trail.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/trail/trail.tsx @@ -7,8 +7,11 @@ import TypeOfContentTitle from '@components/Objects/StyledElements/Titles/TypeOf import GeneralWrapperStyled from '@components/Objects/StyledElements/Wrappers/GeneralWrapper' import { getAPIUrl } from '@services/config/config' import { swrFetcher } from '@services/utils/ts/requests' -import React, { useEffect } from 'react' +import React, { useEffect, useState } from 'react' import useSWR from 'swr' +import { removeCourse } from '@services/courses/activity' +import { revalidateTags } from '@services/utils/ts/requests' +import { useRouter } from 'next/navigation' function Trail(params: any) { let orgslug = params.orgslug @@ -16,28 +19,73 @@ function Trail(params: any) { const access_token = session?.data?.tokens?.access_token; const org = useOrg() as any const orgID = org?.id - const { data: trail, error: error } = useSWR( + const router = useRouter() + const [isQuittingAll, setIsQuittingAll] = useState(false) + const [quittingProgress, setQuittingProgress] = useState(0) + + const { data: trail, error: error, mutate } = useSWR( `${getAPIUrl()}trail/org/${orgID}/trail`, (url) => swrFetcher(url, access_token) ) + const handleQuitAllCourses = async () => { + if (!trail?.runs?.length || isQuittingAll) return; + + setIsQuittingAll(true) + const totalCourses = trail.runs.length; + + try { + for (let i = 0; i < trail.runs.length; i++) { + const run = trail.runs[i]; + await removeCourse(run.course.course_uuid, orgslug, access_token); + setQuittingProgress(Math.round(((i + 1) / totalCourses) * 100)); + } + + await revalidateTags(['courses'], orgslug); + router.refresh(); + await mutate(); + } catch (error) { + console.error('Error quitting courses:', error); + } finally { + setIsQuittingAll(false) + setQuittingProgress(0) + } + } + useEffect(() => { }, [trail, org]) return ( - +
+ + {trail?.runs?.length > 0 && ( + + )} +
{!trail ? ( ) : (
{trail.runs.map((run: any) => ( - <> - - + ))}
)} diff --git a/apps/web/components/Pages/Courses/ActivityIndicators.tsx b/apps/web/components/Pages/Courses/ActivityIndicators.tsx index f5676681..8d37d0e4 100644 --- a/apps/web/components/Pages/Courses/ActivityIndicators.tsx +++ b/apps/web/components/Pages/Courses/ActivityIndicators.tsx @@ -97,6 +97,33 @@ const ActivityTooltipContent = memo(({ ActivityTooltipContent.displayName = 'ActivityTooltipContent'; +// Add new memoized component for chapter tooltip +const ChapterTooltipContent = memo(({ + chapter, + chapterNumber, + totalActivities, + completedActivities +}: { + chapter: any, + chapterNumber: number, + totalActivities: number, + completedActivities: number +}) => ( +
+
+ Chapter {chapterNumber} + + {completedActivities}/{totalActivities} completed + +
+
+ {chapter.name} +
+
+)); + +ChapterTooltipContent.displayName = 'ChapterTooltipContent'; + function ActivityIndicators(props: Props) { const course = props.course const orgslug = props.orgslug @@ -167,6 +194,7 @@ function ActivityIndicators(props: Props) { return `${black_activity_style}` }, [isActivityDone, isActivityCurrent]); + // Keep the allActivities array for navigation purposes only const navigateToPrevious = () => { if (currentActivityIndex > 0) { const prevActivity = allActivities[currentActivityIndex - 1] @@ -183,6 +211,13 @@ function ActivityIndicators(props: Props) { } } + // Add function to count completed activities in a chapter + const getChapterProgress = useMemo(() => (chapterActivities: any[]) => { + return chapterActivities.reduce((acc, activity) => { + return acc + (isActivityDone(activity) ? 1 : 0) + }, 0) + }, [isActivityDone]); + return (
{enableNavigation && ( @@ -197,38 +232,71 @@ function ActivityIndicators(props: Props) { )}
- {allActivities.map((activity: any) => { - const isDone = isActivityDone(activity) - const isCurrent = isActivityCurrent(activity) + {course.chapters.map((chapter: any, chapterIndex: number) => { + const completedActivities = getChapterProgress(chapter.activities); + const isChapterComplete = completedActivities === chapter.activities.length; + return ( - - } - key={activity.activity_uuid} - > - + } - className={`${isCurrent ? 'flex-[2]' : 'flex-1'} mx-1`} > -
- -
+
+
+ {chapterIndex + 1} +
+
+
+
+ {chapter.activities.map((activity: any) => { + const isDone = isActivityDone(activity) + const isCurrent = isActivityCurrent(activity) + return ( + + } + key={activity.activity_uuid} + > + +
+ +
+ ) + })} +
+ ) })}