feat: certificates, landing pages, ai tutor, website update, compliance
This commit is contained in:
@@ -13,8 +13,10 @@
|
||||
import { courseApi } from '$features/course/api';
|
||||
import ContentCreateModal from '$features/course/components/content/content-create-modal.svelte';
|
||||
import CourseCompletionModal from '$features/course/components/ceritficate/course-completion-modal.svelte';
|
||||
import { AiCourseChat } from '$features/ai-assistant';
|
||||
import { aiAssistantPanelDefinition } from '$features/ai-assistant';
|
||||
import { initialChatPrompt, openAiAssistant } from '$features/ai-assistant/utils/store';
|
||||
import { sidePanel, SidePanelRail } from '$features/side-panel';
|
||||
import { transcriptPanelDefinition } from '$features/course/components/lesson/video/transcript-panel-definition';
|
||||
import { get } from 'svelte/store';
|
||||
import { profile } from '$lib/utils/store/user';
|
||||
import { isOrgAdmin } from '$lib/utils/store/org';
|
||||
@@ -27,6 +29,9 @@
|
||||
COURSE_SIDEBAR_STORAGE_KEY
|
||||
} from '$features/course/components/sidebar/constants';
|
||||
|
||||
sidePanel.register(aiAssistantPanelDefinition);
|
||||
sidePanel.register(transcriptPanelDefinition);
|
||||
|
||||
interface Props {
|
||||
children?: import('svelte').Snippet;
|
||||
path: string;
|
||||
@@ -186,5 +191,5 @@
|
||||
{/if}
|
||||
</Sidebar.Inset>
|
||||
|
||||
<AiCourseChat courseId={data.courseId} />
|
||||
<SidePanelRail />
|
||||
</Sidebar.Provider>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { CourseAiTutorSettingsPage } from '$features/ai-tutor-settings';
|
||||
|
||||
let { data } = $props();
|
||||
</script>
|
||||
|
||||
<CourseAiTutorSettingsPage courseId={data.courseId} />
|
||||
@@ -7,12 +7,13 @@
|
||||
let { data } = $props();
|
||||
</script>
|
||||
|
||||
<Page.Root class="mx-auto flex md:max-w-3xl lg:max-w-4xl">
|
||||
<Page.Root class="w-full">
|
||||
<Page.Header>
|
||||
<Page.HeaderContent>
|
||||
<Page.Title>
|
||||
{$t('analytics.title')}
|
||||
</Page.Title>
|
||||
<p class="ui:text-muted-foreground text-sm">{$t('analytics.course_metrics.page_subtitle')}</p>
|
||||
</Page.HeaderContent>
|
||||
<Page.Action>
|
||||
<RefreshPageData />
|
||||
@@ -20,7 +21,7 @@
|
||||
</Page.Header>
|
||||
<Page.Body>
|
||||
{#snippet child()}
|
||||
<AnalyticsPage courseId={data.courseId} courseAnalytics={data.courseAnalytics} />
|
||||
<AnalyticsPage courseAnalytics={data.courseAnalytics} />
|
||||
{/snippet}
|
||||
</Page.Body>
|
||||
</Page.Root>
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
|
||||
const certificateTheme = $derived(courseApi.course?.certificate?.theme ?? '');
|
||||
|
||||
const currentCertificateState = $derived.by(() => getCertificateStateSnapshot(courseApi.course));
|
||||
|
||||
const userRole = $derived.by(() => {
|
||||
const user = courseApi.group.people.find((person) => person.profileId === $profile.id);
|
||||
return user ? Number(user.roleId) : null;
|
||||
@@ -40,7 +38,8 @@
|
||||
description: course.description ?? '',
|
||||
certificate: {
|
||||
isDownloadable: course.certificate?.isDownloadable ?? false,
|
||||
theme: parseCertificateThemeId(course.certificate?.theme) ?? 'professional',
|
||||
theme: parseCertificateThemeId(course.certificate?.theme),
|
||||
design: course.certificate?.design ?? null,
|
||||
deadline: course.certificate?.deadline ?? null,
|
||||
threshold: typeof course.certificate?.threshold === 'number' ? course.certificate.threshold : 100,
|
||||
requiredExerciseId: course.certificate?.requiredExerciseId ?? null,
|
||||
@@ -92,7 +91,8 @@
|
||||
description: courseApi.course.description ?? '',
|
||||
certificate: {
|
||||
isDownloadable: courseApi.course.certificate?.isDownloadable ?? false,
|
||||
theme: certificateTheme || 'professional',
|
||||
theme: certificateTheme || 'classique',
|
||||
design: courseApi.course.certificate?.design,
|
||||
deadline: courseApi.course.certificate?.deadline ?? null,
|
||||
threshold:
|
||||
typeof courseApi.course.certificate?.threshold === 'number' ? courseApi.course.certificate.threshold : 100,
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<script lang="ts">
|
||||
let { children }: { children?: import('svelte').Snippet } = $props();
|
||||
</script>
|
||||
|
||||
{@render children?.()}
|
||||
@@ -0,0 +1,31 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import { Spinner } from '@cio/ui/base/spinner';
|
||||
import { t } from '$lib/utils/functions/translations';
|
||||
import { courseApi } from '$features/course/api';
|
||||
import { profile } from '$lib/utils/store/user';
|
||||
import CertificateEditor from '$features/course/components/ceritficate/editor/certificate-editor.svelte';
|
||||
|
||||
const courseId = $derived(page.params.id ?? '');
|
||||
|
||||
$effect(() => {
|
||||
if (!courseId || !$profile.id) return;
|
||||
courseApi.ensureCourse(courseId, $profile.id);
|
||||
});
|
||||
|
||||
const isReady = $derived(courseApi.course?.id === courseId);
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{courseApi.course?.title ?? $t('course.navItem.certificates.editor.title')}</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="ui:bg-background min-h-screen w-full">
|
||||
{#if isReady}
|
||||
<CertificateEditor {courseId} />
|
||||
{:else}
|
||||
<div class="flex min-h-[60vh] items-center justify-center">
|
||||
<Spinner class="size-8!" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -32,7 +32,7 @@
|
||||
in:fly={{ y: 500, duration: 500 }}
|
||||
out:fly={{ y: 500, duration: 500 }}
|
||||
>
|
||||
<Sidebar.Provider bind:open={sidebarOpen} style="--sidebar-width: 280px">
|
||||
<Sidebar.Provider bind:open={sidebarOpen} style="--sidebar-width: 360px; --sidebar-width-icon: 4rem">
|
||||
<Sidebar.Root side="left" collapsible="icon" class="h-full">
|
||||
<Editor {courseId} bind:course={courseApi.course} {syncCourseStore} onClose={handleClose} />
|
||||
</Sidebar.Root>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<Page.Root class="mx-auto flex w-[90%] px-4 md:max-w-2xl lg:max-w-3xl">
|
||||
<Page.Root class="mx-auto flex w-[90%] px-4 md:max-w-4xl lg:max-w-5xl">
|
||||
{#key data.lessonId}
|
||||
<LessonPage courseId={data.courseId} lessonId={data.lessonId} />
|
||||
{/key}
|
||||
|
||||
Reference in New Issue
Block a user