Files
classroomio/apps/dashboard/src/lib/features/course/utils/content.ts
T
2026-04-27 11:40:38 +01:00

96 lines
2.9 KiB
TypeScript

import type { Course, CourseContentItem, CourseContentSection } from './types';
import { ExerciseIcon, LessonIcon } from '@cio/ui/custom/moving-icons';
import { ContentType as CourseContentType } from '@cio/utils/constants/content';
import TableOfContentsIcon from '@lucide/svelte/icons/table-of-contents';
export type ContentItem = CourseContentItem;
export type ContentSection = CourseContentSection;
export type MentionableContent = {
id: string;
title: string;
type: CourseContentType;
};
export const CONTENT_DEFINITIONS = {
[CourseContentType.Section]: {
label: 'Section',
icon: TableOfContentsIcon
},
[CourseContentType.Lesson]: {
label: 'Lesson',
icon: LessonIcon
},
[CourseContentType.Exercise]: {
label: 'Exercise',
icon: ExerciseIcon
}
} as const;
const EMPTY_CONTENT = {
grouped: false,
sections: [] as ContentSection[],
items: [] as ContentItem[]
};
export function getContentRoute(courseId: string, item: { id: string; type: string }) {
if (item.type === CourseContentType.Lesson) {
return `/courses/${courseId}/lessons/${item.id}`;
}
if (item.type === CourseContentType.Exercise) {
return `/courses/${courseId}/exercises/${item.id}`;
}
if (item.type === CourseContentType.Section) {
return `/courses/${courseId}/lessons#section-${item.id}`;
}
return '';
}
export function getCourseContent(course: Course | null) {
return course?.content ?? EMPTY_CONTENT;
}
const NAVIGABLE_CONTENT_TYPES = [CourseContentType.Lesson, CourseContentType.Exercise] as const;
export function getOrderedNavigableContent(course: Course | null): ContentItem[] {
const content = getCourseContent(course);
const items = content.grouped ? content.sections.flatMap((s) => s.items) : content.items;
return items.filter((item) =>
NAVIGABLE_CONTENT_TYPES.includes(item.type as (typeof NAVIGABLE_CONTENT_TYPES)[number])
);
}
/**
* Flat list of mentionable content for the AI chat @ menu.
* Includes sections (when grouped) interleaved with their lessons/exercises in display order.
*/
export function getMentionableContent(course: Course | null): MentionableContent[] {
const content = getCourseContent(course);
if (!content.grouped) {
return content.items
.filter((item) => NAVIGABLE_CONTENT_TYPES.includes(item.type as (typeof NAVIGABLE_CONTENT_TYPES)[number]))
.map((item) => ({ id: item.id, title: item.title, type: item.type as CourseContentType }));
}
const result: MentionableContent[] = [];
for (const section of content.sections) {
if (section.id !== 'ungrouped' && section.title) {
result.push({ id: section.id, title: section.title, type: CourseContentType.Section });
}
for (const item of section.items) {
if (NAVIGABLE_CONTENT_TYPES.includes(item.type as (typeof NAVIGABLE_CONTENT_TYPES)[number])) {
result.push({ id: item.id, title: item.title, type: item.type as CourseContentType });
}
}
}
return result;
}