Files
classroomio/apps/dashboard/src/lib/features/course/components/new-course-modal.svelte
T
2026-04-27 11:40:38 +01:00

139 lines
4.3 KiB
Svelte

<script lang="ts">
import { preventDefault } from '$lib/utils/functions/svelte';
import { goto } from '$app/navigation';
import { page } from '$app/state';
import { createCourseModal } from '../utils/store';
import { TextareaField } from '@cio/ui/custom/textarea-field';
import { InputField } from '@cio/ui/custom/input-field';
import * as Dialog from '@cio/ui/base/dialog';
import { Button } from '@cio/ui/base/button';
import * as Field from '@cio/ui/base/field';
import { RadioOptionCardGroup } from '@cio/ui/custom/radio-option-card';
import { t } from '$lib/utils/functions/translations';
import type { TCourseType } from '@cio/db/types';
import { courseApi } from '../api';
let step = $state(0);
const options = [
{
id: 'live-class',
title: $t('new_course_modal.live_class_label'),
subtitle: $t('new_course_modal.live_class_subtitle'),
type: 'LIVE_CLASS' as TCourseType,
isDisabled: false
},
{
id: 'self-paced',
title: $t('new_course_modal.self_paced_label'),
subtitle: $t('new_course_modal.self_paced_subtitle'),
type: 'SELF_PACED' as TCourseType,
isDisabled: false
},
{
id: 'compliance',
title: $t('new_course_modal.compliance_label'),
subtitle: $t('new_course_modal.compliance_subtitle'),
type: 'COMPLIANCE' as TCourseType,
isDisabled: false
}
];
const courseTypeOptionsForGroup = options.map((o) => ({
id: o.id,
title: o.title,
description: o.subtitle,
value: o.type
}));
let type = $state(options[0].type);
function onClose(redirectTo) {
goto(redirectTo);
createCourseModal.update(() => ({
title: '',
description: '',
type: '',
emails: '',
tutors: '',
students: ''
}));
}
async function createCourse() {
await courseApi.create({
title: $createCourseModal.title,
description: $createCourseModal.description,
type: type
});
}
let open = $derived(new URLSearchParams(page.url.search).get('create') === 'true');
</script>
{#snippet course_type_selector()}
<Field.Description>{$t('courses.new_course_modal.type_selector_title')}</Field.Description>
<RadioOptionCardGroup options={courseTypeOptionsForGroup} bind:value={type} class="grid-cols-1 md:grid-cols-3" />
{/snippet}
<Dialog.Root
bind:open
onOpenChange={(isOpen) => {
if (!isOpen) onClose(page.url.pathname);
}}
>
<Dialog.Content class="mx-auto w-4/5 max-w-2xl md:w-2/5 md:min-w-[600px]">
<Dialog.Header>
<Dialog.Title>{$t('courses.new_course_modal.heading')}</Dialog.Title>
</Dialog.Header>
{#if step === 0}
<div class="my-4 space-y-4">
{@render course_type_selector()}
<Dialog.Footer>
<Button onclick={() => (step = 1)} disabled={!type}>
{$t('courses.new_course_modal.next')}
</Button>
</Dialog.Footer>
</div>
{:else}
<form onsubmit={preventDefault(createCourse)}>
<div class="mb-4 flex items-end space-x-2">
<InputField
label={$t('courses.new_course_modal.course_name')}
bind:value={$createCourseModal.title}
placeholder={$t('courses.new_course_modal.course_name_placeholder')}
className="w-full"
isRequired={true}
errorMessage={courseApi.errors.title}
autoComplete={false}
/>
</div>
<TextareaField
label={$t('courses.new_course_modal.short_description')}
bind:value={$createCourseModal.description}
rows={4}
placeholder={$t('courses.new_course_modal.short_description_placeholder')}
className="mb-4"
isRequired={true}
errorMessage={courseApi.errors.description}
isAIEnabled={true}
initAIPrompt="Write a 30 word description for a course titled: {$createCourseModal.title}"
/>
<Dialog.Footer>
<Button variant="outline" onclick={() => (step = 0)}>
{$t('courses.new_course_modal.back')}
</Button>
<Button type="submit" disabled={courseApi.isLoading} loading={courseApi.isLoading}>
{$t('courses.new_course_modal.button')}
</Button>
</Dialog.Footer>
</form>
{/if}
</Dialog.Content>
</Dialog.Root>