feat: SCORM

This commit is contained in:
Jannat Patel
2024-11-11 18:25:56 +05:30
parent c45da4313e
commit 2e1aac4931
8 changed files with 230 additions and 57 deletions

View File

@@ -15,20 +15,66 @@
}"
>
<template #body-content>
<FormControl
ref="chapterInput"
label="Title"
v-model="chapter.title"
class="mb-4"
/>
<div class="space-y-4">
<FormControl ref="chapterInput" label="Title" v-model="chapter.title" />
<FormControl
:label="__('Is SCORM Package')"
v-model="chapter.is_scorm_package"
type="checkbox"
/>
<div v-if="chapter.is_scorm_package">
<FileUploader
v-if="!chapter.scorm_package"
:fileTypes="['.zip']"
:validateFile="validateFile"
@success="(file) => (chapter.scorm_package = file)"
>
<template v-slot="{ file, progress, uploading, openFileSelector }">
<div class="mb-4">
<Button @click="openFileSelector" :loading="uploading">
{{
uploading ? `Uploading ${progress}%` : 'Upload an zip file'
}}
</Button>
</div>
</template>
</FileUploader>
<div v-else class="">
<div class="flex items-center">
<div class="border rounded-md p-2 mr-2">
<FileText class="h-5 w-5 stroke-1.5 text-gray-700" />
</div>
<div class="flex flex-col">
<span>
{{ chapter.scorm_package.file_name }}
</span>
<span class="text-sm text-gray-500 mt-1">
{{ getFileSize(chapter.scorm_package.file_size) }}
</span>
</div>
<X
@click="() => (chapter.scorm_package = null)"
class="bg-gray-200 rounded-md cursor-pointer stroke-1.5 w-5 h-5 p-1 ml-4"
/>
</div>
</div>
</div>
</div>
</template>
</Dialog>
</template>
<script setup>
import { Dialog, FormControl, createResource } from 'frappe-ui'
import {
Button,
createResource,
Dialog,
FileUploader,
FormControl,
} from 'frappe-ui'
import { defineModel, reactive, watch, ref } from 'vue'
import { createToast } from '@/utils/'
import { showToast, getFileSize } from '@/utils/'
import { capture } from '@/telemetry'
import { FileText, X } from 'lucide-vue-next'
const show = defineModel()
const outline = defineModel('outline')
@@ -46,18 +92,18 @@ const props = defineProps({
const chapter = reactive({
title: '',
is_scorm_package: 0,
scorm_package: null,
})
const chapterResource = createResource({
url: 'frappe.client.insert',
url: 'lms.lms.api.add_chapter',
makeParams(values) {
return {
doc: {
doctype: 'Course Chapter',
title: chapter.title,
description: chapter.description,
course: props.course,
},
title: chapter.title,
course: props.course,
is_scorm_package: chapter.is_scorm_package,
scorm_package: chapter.scorm_package,
}
},
})
@@ -89,13 +135,16 @@ const chapterReference = createResource({
},
})
const addChapter = (close) => {
const addChapter = async (close) => {
chapterResource.submit(
{},
{
validate() {
if (!chapter.title) {
return 'Title is required'
return __('Title is required')
}
if (chapter.is_scorm_package && !chapter.scorm_package) {
return __('Please upload a SCORM package')
}
},
onSuccess: (data) => {
@@ -104,28 +153,34 @@ const addChapter = (close) => {
{ name: data.name },
{
onSuccess(data) {
chapter.title = ''
cleanChapter()
outline.value.reload()
createToast({
text: 'Chapter added successfully',
icon: 'check',
iconClasses: 'bg-green-600 text-white rounded-md p-px',
})
showToast(
__('Success'),
__('Chapter added successfully'),
'check'
)
},
onError(err) {
showError(err)
showToast(__('Error'), err.messages?.[0] || err, 'x')
},
}
)
close()
},
onError(err) {
showError(err)
showToast(__('Error'), err.messages?.[0] || err, 'x')
},
}
)
}
const cleanChapter = () => {
chapter.title = ''
chapter.is_scorm_package = 0
chapter.scorm_package = null
}
const editChapter = (close) => {
chapterEditResource.submit(
{},
@@ -137,31 +192,16 @@ const editChapter = (close) => {
},
onSuccess() {
outline.value.reload()
createToast({
text: 'Chapter updated successfully',
icon: 'check',
iconClasses: 'bg-green-600 text-white rounded-md p-px',
})
showToast(__('Success'), __('Chapter updated successfully'), 'check')
close()
},
onError(err) {
showError(err)
showToast(__('Error'), err.messages?.[0] || err, 'x')
},
}
)
}
const showError = (err) => {
createToast({
title: 'Error',
text: err.messages?.[0] || err,
icon: 'x',
iconClasses: 'bg-red-600 text-white rounded-md p-px',
position: 'top-center',
timeout: 10,
})
}
watch(
() => props.chapterDetail,
(newChapter) => {
@@ -169,11 +209,18 @@ watch(
}
)
watch(show, () => {
/* watch(show, () => {
if (show.value) {
setTimeout(() => {
chapterInput.value.$el.querySelector('input').focus()
}, 100)
}
})
}) */
const validateFile = (file) => {
let extension = file.name.split('.').pop().toLowerCase()
if (extension !== 'zip') {
return __('Only zip files are allowed')
}
}
</script>