feat: reorder lessons

This commit is contained in:
Jannat Patel
2024-07-09 22:45:45 +05:30
parent 8edfe041c3
commit 2ecc07ee58
5 changed files with 128 additions and 54 deletions

View File

@@ -29,7 +29,9 @@
"tailwindcss": "^3.3.3",
"vue": "^3.4.23",
"vue-chartjs": "^5.3.0",
"vue-router": "^4.0.12"
"vue-draggable-next": "^2.2.1",
"vue-router": "^4.0.12",
"vuedraggable": "4.1.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.3",

View File

@@ -39,45 +39,53 @@
</div>
</DisclosureButton>
<DisclosurePanel>
<div v-for="lesson in chapter.lessons" :key="lesson.name">
<div class="outline-lesson pl-8 py-2 pr-4">
<router-link
:to="{
name: allowEdit ? 'CreateLesson' : 'Lesson',
params: {
courseName: courseName,
chapterNumber: lesson.number.split('.')[0],
lessonNumber: lesson.number.split('.')[1],
},
}"
>
<div class="flex items-center text-sm leading-5 group">
<MonitorPlay
v-if="lesson.icon === 'icon-youtube'"
class="h-4 w-4 text-gray-900 stroke-1 mr-2"
/>
<HelpCircle
v-else-if="lesson.icon === 'icon-quiz'"
class="h-4 w-4 text-gray-900 stroke-1 mr-2"
/>
<FileText
v-else-if="lesson.icon === 'icon-list'"
class="h-4 w-4 text-gray-900 stroke-1 mr-2"
/>
{{ lesson.title }}
<Trash2
v-if="allowEdit"
@click.prevent="trashLesson(lesson.name, chapter.name)"
class="h-4 w-4 stroke-1.5 text-gray-700 ml-auto invisible group-hover:visible"
/>
<Check
v-if="lesson.is_complete"
class="h-4 w-4 text-green-700 ml-2"
/>
</div>
</router-link>
</div>
</div>
<Draggable
:list="chapter.lessons"
item-key="name"
group="items"
@end="updateOutline"
:data-chapter="chapter.name"
>
<template #item="{ element: lesson }">
<div class="outline-lesson pl-8 py-2 pr-4">
<router-link
:to="{
name: allowEdit ? 'CreateLesson' : 'Lesson',
params: {
courseName: courseName,
chapterNumber: lesson.number.split('.')[0],
lessonNumber: lesson.number.split('.')[1],
},
}"
>
<div class="flex items-center text-sm leading-5 group">
<MonitorPlay
v-if="lesson.icon === 'icon-youtube'"
class="h-4 w-4 text-gray-900 stroke-1 mr-2"
/>
<HelpCircle
v-else-if="lesson.icon === 'icon-quiz'"
class="h-4 w-4 text-gray-900 stroke-1 mr-2"
/>
<FileText
v-else-if="lesson.icon === 'icon-list'"
class="h-4 w-4 text-gray-900 stroke-1 mr-2"
/>
{{ lesson.title }}
<Trash2
v-if="allowEdit"
@click.prevent="trashLesson(lesson.name, chapter.name)"
class="h-4 w-4 stroke-1.5 text-gray-700 ml-auto invisible group-hover:visible"
/>
<Check
v-if="lesson.is_complete"
class="h-4 w-4 text-green-700 ml-2"
/>
</div>
</router-link>
</div>
</template>
</Draggable>
<div v-if="allowEdit" class="flex mt-2 mb-4 pl-8">
<router-link
:to="{
@@ -111,6 +119,7 @@
<script setup>
import { Button, createResource } from 'frappe-ui'
import { ref } from 'vue'
import Draggable from 'vuedraggable'
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/vue'
import {
ChevronRight,
@@ -176,6 +185,17 @@ const deleteLesson = createResource({
},
})
const updateLessonIndex = createResource({
url: 'lms.lms.api.update_lesson_index',
makeParams(values) {
return {
lesson: values.lesson,
chapter: values.chapter,
idx: values.idx,
}
},
})
const trashLesson = (lessonName, chapterName) => {
deleteLesson.submit({
lesson: lessonName,
@@ -195,6 +215,18 @@ const openChapterModal = (chapter = null) => {
const getCurrentChapter = () => {
return currentChapter.value
}
const updateOutline = (e) => {
console.log(e)
const sourceChapter = e.from.dataset.chapter
const targetChapter = e.to.dataset.chapter
const lesson = e.item.__draggable_context.element.name
updateLessonIndex.submit({
lesson: lesson,
chapter: sourceChapter,
idx: e.newIndex,
})
}
</script>
<style>
.outline-lesson:has(.router-link-active) {

View File

@@ -7,19 +7,6 @@
>
<Breadcrumbs class="h-7" :items="breadcrumbs" />
<div class="flex items-center mt-3 md:mt-0">
<router-link
v-if="courseResource.data"
:to="{
name: 'CourseDetail',
params: { courseName: courseResource.data.name },
}"
>
<Button>
<span>
{{ __('View Course') }}
</span>
</Button>
</router-link>
<Button variant="solid" @click="submitCourse()" class="ml-2">
<span>
{{ __('Save') }}
@@ -222,7 +209,12 @@ import {
reactive,
watch,
} from 'vue'
import { convertToTitleCase, showToast, getFileSize } from '../utils'
import {
convertToTitleCase,
showToast,
getFileSize,
updateDocumentTitle,
} from '../utils'
import Link from '@/components/Controls/Link.vue'
import { FileText, X } from 'lucide-vue-next'
import { useRouter } from 'vue-router'
@@ -492,4 +484,13 @@ const breadcrumbs = computed(() => {
})
return crumbs
})
const pageMeta = computed(() => {
return {
title: 'Create a Course',
description: 'Create or edit a course for your learning system.',
}
})
updateDocumentTitle(pageMeta)
</script>

View File

@@ -1865,12 +1865,18 @@ socket.io-parser@~4.2.4:
"@socket.io/component-emitter" "~3.1.0"
debug "~4.3.1"
sortablejs@1.14.0:
version "1.14.0"
resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.14.0.tgz#6d2e17ccbdb25f464734df621d4f35d4ab35b3d8"
integrity sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==
source-map-js@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
name string-width-cjs
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -1889,6 +1895,7 @@ string-width@^5.0.1, string-width@^5.1.2:
strip-ansi "^7.0.1"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
name strip-ansi-cjs
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -2025,6 +2032,11 @@ vue-demi@>=0.13.0, vue-demi@>=0.14.5, vue-demi@>=0.14.7:
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.8.tgz#00335e9317b45e4a68d3528aaf58e0cec3d5640a"
integrity sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==
vue-draggable-next@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/vue-draggable-next/-/vue-draggable-next-2.2.1.tgz#adbe98c74610cca8f4eb63f92042681f96920451"
integrity sha512-EAMS1IRHF0kZO0o5PMOinsQsXIqsrKT1hKmbICxG3UEtn7zLFkLxlAtajcCcUTisNvQ6TtCB5COjD9a1raNADw==
vue-router@^4.0.12:
version "4.3.2"
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.3.2.tgz#08096c7765dacc6832f58e35f7a081a8b34116a7"
@@ -2043,6 +2055,13 @@ vue@^3.4.23:
"@vue/server-renderer" "3.4.27"
"@vue/shared" "3.4.27"
vuedraggable@4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/vuedraggable/-/vuedraggable-4.1.0.tgz#edece68adb8a4d9e06accff9dfc9040e66852270"
integrity sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==
dependencies:
sortablejs "1.14.0"
w3c-keyname@^2.2.0:
version "2.2.8"
resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz#7b17c8c6883d4e8b86ac8aba79d39e880f8869c5"

View File

@@ -483,3 +483,23 @@ def delete_sidebar_item(webpage):
def delete_lesson(lesson, chapter):
frappe.db.delete("Lesson Reference", {"parent": chapter, "lesson": lesson})
frappe.db.delete("Course Lesson", lesson)
@frappe.whitelist()
def update_lesson_index(lesson, chapter, idx):
name = frappe.db.get_value(
"Lesson Reference",
{"lesson": lesson, "parent": chapter},
["name", "idx", "parent", "lesson"],
)
print(name)
frappe.db.set_value(
"Lesson Reference",
{
"lesson": lesson,
"parent": chapter,
},
"idx",
idx,
)
frappe.db.commit()