diff --git a/frontend/src/components/AppSidebar.vue b/frontend/src/components/AppSidebar.vue index 386ed715..8548333c 100644 --- a/frontend/src/components/AppSidebar.vue +++ b/frontend/src/components/AppSidebar.vue @@ -18,7 +18,9 @@ { getCurrentEditor().blocks.insert('upload', data) } -const getBlocksCount = () => { - return getCurrentEditor().blocks.getBlocksCount -} - const validateFile = (file) => { let extension = file.name.split('.').pop().toLowerCase() if (!['jpg', 'jpeg', 'png', 'mp4', 'mov', 'mp3'].includes(extension)) { diff --git a/frontend/src/components/UserDropdown.vue b/frontend/src/components/UserDropdown.vue index 63e1b770..8e39867f 100644 --- a/frontend/src/components/UserDropdown.vue +++ b/frontend/src/components/UserDropdown.vue @@ -11,7 +11,12 @@ : 'hover:bg-gray-200 px-2 w-52' " > - + +
- Learning + + {{ branding.data?.brand_name }} + + Learning
{{ convertToTitleCase(user.split('@')[0]) }} @@ -49,6 +57,7 @@ import { Dropdown } from 'frappe-ui' import { ChevronDown, LogIn, LogOut, User } from 'lucide-vue-next' import { useRouter } from 'vue-router' import { convertToTitleCase } from '../utils' +import { onMounted } from 'vue' const router = useRouter() const props = defineProps({ @@ -58,8 +67,9 @@ const props = defineProps({ }, }) -const { logout, user } = sessionStore() +const { logout, user, branding } = sessionStore() let { isLoggedIn } = sessionStore() + const userDropdownOptions = [ /* { icon: User, diff --git a/frontend/src/pages/CreateCourse.vue b/frontend/src/pages/CreateCourse.vue index d87ce9f2..ff8ca7a8 100644 --- a/frontend/src/pages/CreateCourse.vue +++ b/frontend/src/pages/CreateCourse.vue @@ -187,14 +187,16 @@ import { FormControl, FileUploader, } from 'frappe-ui' -import { inject, onMounted, computed, ref, reactive } from 'vue' +import { inject, onMounted, computed, ref, reactive, watch } from 'vue' import { convertToTitleCase, showToast, getFileSize } from '../utils' import Link from '@/components/Controls/Link.vue' import { FileText, X } from 'lucide-vue-next' +import { useRouter } from 'vue-router' import CourseOutline from '@/components/CourseOutline.vue' const user = inject('$user') const newTag = ref('') +const router = useRouter() const props = defineProps({ courseName: { @@ -318,8 +320,12 @@ const submitCourse = () => { ) } else { courseCreationResource.submit(course, { - onSuccess() { + onSuccess(data) { showToast('Success', 'Course created successfully', 'check') + router.push({ + name: 'CreateCourse', + params: { courseName: data.name }, + }) }, onError(err) { showToast(err) @@ -347,6 +353,15 @@ const validateMandatoryFields = () => { } } +watch( + () => props.courseName !== 'new', + (newVal) => { + if (newVal) { + courseResource.reload() + } + } +) + const validateFile = (file) => { let extension = file.name.split('.').pop().toLowerCase() if (!['jpg', 'jpeg', 'png'].includes(extension)) { diff --git a/frontend/src/pages/CreateLesson.vue b/frontend/src/pages/CreateLesson.vue index a0ebd168..18c985cc 100644 --- a/frontend/src/pages/CreateLesson.vue +++ b/frontend/src/pages/CreateLesson.vue @@ -73,17 +73,19 @@ import { Button, createDocumentResource, } from 'frappe-ui' -import { computed, reactive, onMounted, inject, ref } from 'vue' +import { computed, reactive, onMounted, inject, ref, watch } from 'vue' import EditorJS from '@editorjs/editorjs' import { createToast } from '../utils' import LessonPlugins from '@/components/LessonPlugins.vue' import { getEditorTools } from '../utils' import { ChevronRight } from 'lucide-vue-next' +import { useRouter } from 'vue-router' const editor = ref(null) const instructorEditor = ref(null) const user = inject('$user') const openInstructorEditor = ref(false) +const router = useRouter() const props = defineProps({ courseName: { @@ -319,6 +321,7 @@ const createNewLesson = () => { { onSuccess() { showToast('Success', 'Lesson created successfully', 'check') + lessonDetails.reload() }, } ) diff --git a/frontend/src/pages/Lesson.vue b/frontend/src/pages/Lesson.vue index 55e4a02c..3193a8f8 100644 --- a/frontend/src/pages/Lesson.vue +++ b/frontend/src/pages/Lesson.vue @@ -114,7 +114,10 @@
@@ -233,8 +236,7 @@ const lesson = createResource({ markProgress(data) if (data.content) editor = renderEditor('editor', data.content) - - if (data.instructor_content) + if (data.instructor_content?.blocks?.length) instructorEditor = renderEditor( 'instructor-content', data.instructor_content @@ -253,7 +255,8 @@ const renderEditor = (holder, content) => { } const markProgress = (data) => { - if (!data.progress) progress.submit() + console.log(user.data) + if (user.data && !data.progress) progress.submit() } const current_lesson = createResource({ diff --git a/frontend/src/stores/session.js b/frontend/src/stores/session.js index 564db2d8..c4ced34f 100644 --- a/frontend/src/stores/session.js +++ b/frontend/src/stores/session.js @@ -41,10 +41,20 @@ export const sessionStore = defineStore('lms-session', () => { }, }) + const branding = createResource({ + url: 'lms.lms.api.get_branding', + auto: true, + cache: true, + onSuccess(data) { + document.querySelector("link[rel='icon']").href = data.favicon + }, + }) + return { user, isLoggedIn, login, logout, + branding, } }) diff --git a/frontend/src/utils/index.js b/frontend/src/utils/index.js index ac793933..2aac40d7 100644 --- a/frontend/src/utils/index.js +++ b/frontend/src/utils/index.js @@ -117,9 +117,6 @@ export function getEditorTools() { paragraph: { class: Paragraph, inlineToolbar: true, - config: { - preserveBlank: true, - }, }, list: { class: NestedList, diff --git a/frontend/src/utils/upload.js b/frontend/src/utils/upload.js index e0ccddb0..401c6319 100644 --- a/frontend/src/utils/upload.js +++ b/frontend/src/utils/upload.js @@ -15,11 +15,11 @@ export class Upload { } renderUpload(file) { - if (file.file_type == 'video') { + if (this.isVideo(file.file_type)) { return `` - } else if (file.file_type == 'audio') { + } else if (this.isAudio(file.file_type)) { return `` @@ -40,4 +40,12 @@ export class Upload { file_type: this.data.file_type, } } + + isVideo(type) { + return ['mov', 'mp4', 'avi', 'mkv', 'webm'].includes(type.toLowerCase()) + } + + isAudio(type) { + return ['mp3', 'wav', 'ogg'].includes(type.toLowerCase()) + } } diff --git a/lms/lms/api.py b/lms/lms/api.py index 64c3b4af..9a8addd6 100644 --- a/lms/lms/api.py +++ b/lms/lms/api.py @@ -278,3 +278,13 @@ def get_file_info(file_url): "File", {"file_url": file_url}, ["file_name", "file_size", "file_url"], as_dict=1 ) return file_info + + +@frappe.whitelist(allow_guest=True) +def get_branding(): + """Get branding details.""" + return { + "brand_name": frappe.db.get_single_value("Website Settings", "app_name"), + "brand_html": frappe.db.get_single_value("Website Settings", "brand_html"), + "favicon": frappe.db.get_single_value("Website Settings", "favicon"), + } diff --git a/lms/lms/doctype/lms_certificate/lms_certificate.py b/lms/lms/doctype/lms_certificate/lms_certificate.py index 28e8864e..11934582 100644 --- a/lms/lms/doctype/lms_certificate/lms_certificate.py +++ b/lms/lms/doctype/lms_certificate/lms_certificate.py @@ -15,7 +15,11 @@ class LMSCertificate(Document): def after_insert(self): if not frappe.flags.in_test: - self.send_mail() + outgoing_email_account = frappe.get_cached_value( + "Email Account", {"default_outgoing": 1, "enable_outgoing": 1}, "name" + ) + if outgoing_email_account: + self.send_mail() def send_mail(self): subject = _("Congratulations on getting certified!") diff --git a/lms/lms/utils.py b/lms/lms/utils.py index 9c59eb98..1412a3df 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -161,7 +161,6 @@ def get_lesson_details(chapter): ) lesson_details.number = f"{chapter.idx}.{row.idx}" lesson_details.icon = get_lesson_icon(lesson_details.body) - lesson_details.is_complete = get_progress(lesson_details.course, lesson_details.name) lessons.append(lesson_details) return lessons diff --git a/lms/templates/emails/certification.html b/lms/templates/emails/certification.html index f7d2d8c9..3e8b261b 100644 --- a/lms/templates/emails/certification.html +++ b/lms/templates/emails/certification.html @@ -10,7 +10,7 @@ {{ _("With this certification, you can now showcase your updated skills and share your achievement with your colleagues and on LinkedIn. To access your certificate, please click on the link provided below. Make sure you are logged in to the portal.") }}


-{{ _("Certificate Link") }} +{{ _("Certificate Link") }}

{{ _("Once again, congratulations on this significant accomplishment.")}} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..fb57ccd1 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + +