fix: lesson auto save

This commit is contained in:
Jannat Patel
2024-08-05 18:14:35 +05:30
parent eed330662b
commit 8adfe247b2
13 changed files with 113 additions and 76 deletions

View File

@@ -100,7 +100,7 @@ import { ChevronRight, Plus } from 'lucide-vue-next'
import { createResource, Button } from 'frappe-ui' import { createResource, Button } from 'frappe-ui'
import PageModal from '@/components/Modals/PageModal.vue' import PageModal from '@/components/Modals/PageModal.vue'
const { user } = sessionStore() const { user, sidebarSettings } = sessionStore()
const { userResource } = usersStore() const { userResource } = usersStore()
const socket = inject('$socket') const socket = inject('$socket')
const unreadCount = ref(0) const unreadCount = ref(0)
@@ -115,6 +115,20 @@ onMounted(() => {
unreadNotifications.reload() unreadNotifications.reload()
}) })
addNotifications() addNotifications()
sidebarSettings.reload(
{},
{
onSuccess(data) {
Object.keys(data).forEach((key) => {
if (!parseInt(data[key])) {
sidebarLinks.value = sidebarLinks.value.filter(
(link) => link.label.toLowerCase().split(' ').join('_') !== key
)
}
})
},
}
)
}) })
const unreadNotifications = createResource({ const unreadNotifications = createResource({
@@ -153,21 +167,6 @@ const addNotifications = () => {
} }
} }
const sidebarSettings = createResource({
url: 'lms.lms.api.get_sidebar_settings',
cache: 'Sidebar Settings',
auto: true,
onSuccess(data) {
Object.keys(data).forEach((key) => {
if (!parseInt(data[key])) {
sidebarLinks.value = sidebarLinks.value.filter(
(link) => link.label.toLowerCase().split(' ').join('_') !== key
)
}
})
},
})
const openPageModal = (link) => { const openPageModal = (link) => {
showPageModal.value = true showPageModal.value = true
pageToEdit.value = link pageToEdit.value = link

View File

@@ -50,7 +50,7 @@
<div class="outline-lesson pl-8 py-2 pr-4"> <div class="outline-lesson pl-8 py-2 pr-4">
<router-link <router-link
:to="{ :to="{
name: allowEdit ? 'CreateLesson' : 'Lesson', name: allowEdit ? 'LessonForm' : 'Lesson',
params: { params: {
courseName: courseName, courseName: courseName,
chapterNumber: lesson.number.split('.')[0], chapterNumber: lesson.number.split('.')[0],
@@ -89,7 +89,7 @@
<div v-if="allowEdit" class="flex mt-2 mb-4 pl-8"> <div v-if="allowEdit" class="flex mt-2 mb-4 pl-8">
<router-link <router-link
:to="{ :to="{
name: 'CreateLesson', name: 'LessonForm',
params: { params: {
courseName: courseName, courseName: courseName,
chapterNumber: chapter.idx, chapterNumber: chapter.idx,

View File

@@ -4,14 +4,14 @@
<slot /> <slot />
</div> </div>
<div <div
v-if="tabs" v-if="sidebarSettings.data"
class="fixed flex justify-around border-t border-gray-300 bottom-0 z-10 w-full bg-white standalone:pb-4" class="fixed flex justify-around border-t border-gray-300 bottom-0 z-10 w-full bg-white standalone:pb-4"
:style="{ :style="{
gridTemplateColumns: `repeat(${tabs.length}, minmax(0, 1fr))`, gridTemplateColumns: `repeat(${sidebarLinks.length}, minmax(0, 1fr))`,
}" }"
> >
<button <button
v-for="tab in tabs" v-for="tab in sidebarLinks"
:key="tab.label" :key="tab.label"
:class="isVisible(tab) ? 'block' : 'hidden'" :class="isVisible(tab) ? 'block' : 'hidden'"
class="flex flex-col items-center justify-center py-3 transition active:scale-95" class="flex flex-col items-center justify-center py-3 transition active:scale-95"
@@ -29,21 +29,38 @@
<script setup> <script setup>
import { getSidebarLinks } from '../utils' import { getSidebarLinks } from '../utils'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { computed } from 'vue' import { computed, ref, onMounted } from 'vue'
import { sessionStore } from '@/stores/session' import { sessionStore } from '@/stores/session'
import { usersStore } from '@/stores/user' import { usersStore } from '@/stores/user'
import * as icons from 'lucide-vue-next' import * as icons from 'lucide-vue-next'
const { logout, user } = sessionStore() const { logout, user, sidebarSettings } = sessionStore()
let { isLoggedIn } = sessionStore() let { isLoggedIn } = sessionStore()
const router = useRouter() const router = useRouter()
let { userResource } = usersStore() let { userResource } = usersStore()
const sidebarLinks = ref(getSidebarLinks())
const tabs = computed(() => { onMounted(() => {
let links = getSidebarLinks() sidebarSettings.reload(
{},
{
onSuccess(data) {
Object.keys(data).forEach((key) => {
if (!parseInt(data[key])) {
sidebarLinks.value = sidebarLinks.value.filter(
(link) => link.label.toLowerCase().split(' ').join('_') !== key
)
}
})
addAccessLinks()
},
}
)
})
const addAccessLinks = () => {
if (user) { if (user) {
links.push({ sidebarLinks.value.push({
label: 'Profile', label: 'Profile',
icon: 'UserRound', icon: 'UserRound',
activeFor: [ activeFor: [
@@ -54,18 +71,17 @@ const tabs = computed(() => {
'ProfileRoles', 'ProfileRoles',
], ],
}) })
links.push({ sidebarLinks.value.push({
label: 'Log out', label: 'Log out',
icon: 'LogOut', icon: 'LogOut',
}) })
} else { } else {
links.push({ sidebarLinks.value.push({
label: 'Log in', label: 'Log in',
icon: 'LogIn', icon: 'LogIn',
}) })
} }
return links }
})
let isActive = (tab) => { let isActive = (tab) => {
return tab.activeFor?.includes(router.currentRoute.value.name) return tab.activeFor?.includes(router.currentRoute.value.name)

View File

@@ -5,7 +5,7 @@
> >
<Breadcrumbs <Breadcrumbs
class="h-7" class="h-7"
:items="[{ label: __('All Batches'), route: { name: 'Batches' } }]" :items="[{ label: __('Batches'), route: { name: 'Batches' } }]"
/> />
<div class="flex space-x-2"> <div class="flex space-x-2">
<div class="w-40"> <div class="w-40">
@@ -25,7 +25,7 @@
> >
<Button variant="solid"> <Button variant="solid">
<template #prefix> <template #prefix>
<Plus class="h-4 w-4" /> <Plus class="h-4 w-4 stroke-1.5" />
</template> </template>
{{ __('New Batch') }} {{ __('New Batch') }}
</Button> </Button>

View File

@@ -6,9 +6,10 @@
<div> <div>
<FormControl <FormControl
type="text" type="text"
placeholder="Search Participants" placeholder="Search"
v-model="searchQuery" v-model="searchQuery"
@input="participants.reload()" @input="participants.reload()"
class="w-40"
> >
<template #prefix> <template #prefix>
<Search class="w-4 stroke-1.5 text-gray-600" name="search" /> <Search class="w-4 stroke-1.5 text-gray-600" name="search" />

View File

@@ -5,19 +5,21 @@
> >
<Breadcrumbs <Breadcrumbs
class="h-7" class="h-7"
:items="[{ label: __('All Courses'), route: { name: 'Courses' } }]" :items="[{ label: __('Courses'), route: { name: 'Courses' } }]"
/> />
<div class="flex space-x-2"> <div class="flex space-x-2 justify-end">
<FormControl <div class="w-36">
type="text" <FormControl
placeholder="Search Course" type="text"
v-model="searchQuery" placeholder="Search"
@input="courses.reload()" v-model="searchQuery"
> @input="courses.reload()"
<template #prefix> >
<Search class="w-4 stroke-1.5 text-gray-600" name="search" /> <template #prefix>
</template> <Search class="w-4 h-4 stroke-1.5" name="search" />
</FormControl> </template>
</FormControl>
</div>
<router-link <router-link
:to="{ :to="{
name: 'CreateCourse', name: 'CreateCourse',

View File

@@ -58,7 +58,7 @@
<router-link <router-link
v-if="allowEdit()" v-if="allowEdit()"
:to="{ :to="{
name: 'CreateLesson', name: 'LessonForm',
params: { params: {
courseName: courseName, courseName: courseName,
chapterNumber: props.chapterNumber, chapterNumber: props.chapterNumber,

View File

@@ -80,6 +80,7 @@ const editor = ref(null)
const instructorEditor = ref(null) const instructorEditor = ref(null)
const user = inject('$user') const user = inject('$user')
const openInstructorEditor = ref(false) const openInstructorEditor = ref(false)
let autoSaveInterval
const props = defineProps({ const props = defineProps({
courseName: { courseName: {
@@ -134,32 +135,45 @@ const lessonDetails = createResource({
lesson[key] = data.lesson[key] lesson[key] = data.lesson[key]
}) })
lesson.include_in_preview = data.include_in_preview ? true : false lesson.include_in_preview = data.include_in_preview ? true : false
editor.value.isReady.then(() => { addLessonContent(data)
if (data.lesson.content) { addInstructorNotes(data)
editor.value.render(JSON.parse(data.lesson.content)) enableAutoSave()
} else if (data.lesson.body) {
let blocks = convertToJSON(data.lesson)
editor.value.render({
blocks: blocks,
})
}
})
instructorEditor.value.isReady.then(() => {
if (data.lesson.instructor_content) {
instructorEditor.value.render(
JSON.parse(data.lesson.instructor_content)
)
} else if (data.lesson.instructor_notes) {
let blocks = convertToJSON(data.lesson)
instructorEditor.value.render({
blocks: blocks,
})
}
})
} }
}, },
}) })
const addLessonContent = (data) => {
editor.value.isReady.then(() => {
if (data.lesson.content) {
editor.value.render(JSON.parse(data.lesson.content))
} else if (data.lesson.body) {
let blocks = convertToJSON(data.lesson)
editor.value.render({
blocks: blocks,
})
}
})
}
const addInstructorNotes = (data) => {
instructorEditor.value.isReady.then(() => {
if (data.lesson.instructor_content) {
instructorEditor.value.render(JSON.parse(data.lesson.instructor_content))
} else if (data.lesson.instructor_notes) {
let blocks = convertToJSON(data.lesson)
instructorEditor.value.render({
blocks: blocks,
})
}
})
}
const enableAutoSave = () => {
autoSaveInterval = setInterval(() => {
saveLesson()
}, 10000)
}
const newLessonResource = createResource({ const newLessonResource = createResource({
url: 'frappe.client.insert', url: 'frappe.client.insert',
makeParams(values) { makeParams(values) {
@@ -357,9 +371,6 @@ const editCurrentLesson = () => {
validate() { validate() {
return validateLesson() return validateLesson()
}, },
onSuccess() {
showToast('Success', 'Lesson updated successfully', 'check')
},
onError(err) { onError(err) {
showToast('Error', err.message, 'x') showToast('Error', err.message, 'x')
}, },
@@ -418,7 +429,7 @@ const breadcrumbs = computed(() => {
crumbs.push({ crumbs.push({
label: lessonDetails?.data?.lesson ? 'Edit Lesson' : 'Create Lesson', label: lessonDetails?.data?.lesson ? 'Edit Lesson' : 'Create Lesson',
route: { route: {
name: 'CreateLesson', name: 'LessonForm',
params: { params: {
courseName: props.courseName, courseName: props.courseName,
chapterNumber: props.chapterNumber, chapterNumber: props.chapterNumber,

View File

@@ -16,7 +16,7 @@
<h2 class="mb-3 text-lg font-semibold text-gray-900"> <h2 class="mb-3 text-lg font-semibold text-gray-900">
{{ __('Achievements') }} {{ __('Achievements') }}
</h2> </h2>
<div class="grid grid-cols-5 gap-4"> <div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4">
<div v-for="badge in badges.data"> <div v-for="badge in badges.data">
<Popover trigger="hover" :leaveDelay="Number(0.01)"> <Popover trigger="hover" :leaveDelay="Number(0.01)">
<template #target> <template #target>

View File

@@ -103,8 +103,8 @@ const routes = [
}, },
{ {
path: '/courses/:courseName/learn/:chapterNumber-:lessonNumber/edit', path: '/courses/:courseName/learn/:chapterNumber-:lessonNumber/edit',
name: 'CreateLesson', name: 'LessonForm',
component: () => import('@/pages/CreateLesson.vue'), component: () => import('@/pages/LessonForm.vue'),
props: true, props: true,
}, },
{ {

View File

@@ -53,11 +53,18 @@ export const sessionStore = defineStore('lms-session', () => {
}, },
}) })
const sidebarSettings = createResource({
url: 'lms.lms.api.get_sidebar_settings',
cache: 'Sidebar Settings',
auto: false,
})
return { return {
user, user,
isLoggedIn, isLoggedIn,
login, login,
logout, logout,
branding, branding,
sidebarSettings,
} }
}) })

View File

@@ -425,7 +425,7 @@ export function getSidebarLinks() {
'CourseDetail', 'CourseDetail',
'Lesson', 'Lesson',
'CreateCourse', 'CreateCourse',
'CreateLesson', 'LessonForm',
], ],
}, },
{ {

View File

@@ -184,6 +184,7 @@ jinja = {
"lms.lms.utils.get_lesson_index", "lms.lms.utils.get_lesson_index",
"lms.lms.utils.get_lesson_url", "lms.lms.utils.get_lesson_url",
"lms.page_renderers.get_profile_url", "lms.page_renderers.get_profile_url",
"lms.overrides.user.get_palette",
], ],
"filters": [], "filters": [],
} }