feat: students should move to next lesson on click go to lesson (#230)
* completion * completion * PR Fixes * PR Fixes * fix: progress bug on home page * chore: fix lesson completion issue --------- Co-authored-by: Rotimi Best <[email protected]>
This commit is contained in:
co-authored by
Rotimi Best
parent
db38756cbf
commit
1277bcbfc6
@@ -9,6 +9,7 @@
|
||||
import { profile } from '$lib/utils/store/user';
|
||||
import { fetchCourse } from '$lib/utils/services/courses';
|
||||
import { globalStore } from '$lib/utils/store/app';
|
||||
import { lessons } from '../Course/components/Lesson/store/lessons';
|
||||
|
||||
export let courseId = '';
|
||||
export let path = '';
|
||||
@@ -23,6 +24,7 @@
|
||||
|
||||
isFetching = true;
|
||||
course.set(defaultCourse);
|
||||
lessons.set([]);
|
||||
|
||||
const { data: _data } = await fetchCourse(courseId);
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
<a
|
||||
rel="prefetch"
|
||||
bind:this={target}
|
||||
href={isOnLandingPage ? `/course/${slug}` : `/courses/${id}`}
|
||||
href={isOnLandingPage ? `/course/${slug}` : `/courses/${id}${isLMS ? '/lessons?next=true' : ''}`}
|
||||
class="text-black border border-gray dark:border-neutral-600 rounded w-full max-w-[320px] relative hover:scale-95 transition-all ease-in-out"
|
||||
>
|
||||
<div class="p-4">
|
||||
@@ -122,7 +122,7 @@
|
||||
|
||||
{#if isLMS}
|
||||
<PrimaryButton
|
||||
label={'Continue Course'}
|
||||
label="Continue Course"
|
||||
variant={VARIANTS.OUTLINED}
|
||||
className="rounded-none text-primary-600"
|
||||
/>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
const gotoCourse = (id: string | undefined) => {
|
||||
if (!id) return;
|
||||
goto(`/courses/${id}`);
|
||||
goto(`/courses/${id}/lessons?next=true`);
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -41,7 +41,9 @@
|
||||
</span>
|
||||
<div class="relative bg-[#EAEAEA] w-full h-1">
|
||||
<div
|
||||
style="width:{course.progress_rate}%"
|
||||
style="width: {Math.round(
|
||||
((course?.progress_rate ?? 0) / (course?.total_lessons ?? 0)) * 100
|
||||
) || 0}%"
|
||||
class={`absolute top-0 left-0 bg-primary-700 h-full`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -175,8 +175,17 @@ export function updateLesson(lesson: any, lessonId: Lesson['id']) {
|
||||
.match({ id: lessonId });
|
||||
}
|
||||
|
||||
export function updateLessonCompletion(completion: LessonCompletion) {
|
||||
return supabase.from('lesson_completion').upsert(completion);
|
||||
export function updateLessonCompletion(completion: LessonCompletion, shouldUpdate: boolean) {
|
||||
if (shouldUpdate) {
|
||||
return supabase
|
||||
.from('lesson_completion')
|
||||
.update({
|
||||
is_complete: completion.is_complete
|
||||
})
|
||||
.eq('id', completion.id);
|
||||
} else {
|
||||
return supabase.from('lesson_completion').insert(completion);
|
||||
}
|
||||
}
|
||||
|
||||
export function deleteLesson(lessonId: Lesson['id']) {
|
||||
|
||||
@@ -26,13 +26,17 @@
|
||||
import { course, group } from '$lib/components/Course/store';
|
||||
import DateField from '$lib/components/Form/Date.svelte';
|
||||
import type { Lesson } from '$lib/utils/types';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
export let data;
|
||||
|
||||
const query = new URLSearchParams($page.url.search);
|
||||
|
||||
let lessonEditing: string | undefined;
|
||||
let lessonToDelete: Lesson | undefined;
|
||||
let isStudent = true;
|
||||
let openDeleteModal = false;
|
||||
let isStudent: boolean = true;
|
||||
let openDeleteModal: boolean = false;
|
||||
let isFetching: boolean = false;
|
||||
|
||||
const flipDurationMs = 300;
|
||||
|
||||
@@ -81,6 +85,30 @@
|
||||
return index + 1;
|
||||
}
|
||||
}
|
||||
|
||||
function findFirstIncompleteLesson() {
|
||||
return $lessons.find(
|
||||
(lesson) =>
|
||||
lesson.lesson_completion &&
|
||||
lesson.lesson_completion.length === 0 &&
|
||||
lesson.is_unlocked === true
|
||||
);
|
||||
}
|
||||
|
||||
function onNextQuery(lessons) {
|
||||
if (!isFetching && lessons.length > 0) {
|
||||
const incompleteLesson = findFirstIncompleteLesson();
|
||||
|
||||
if (incompleteLesson) {
|
||||
goto(`/courses/${data.courseId}/lessons/${incompleteLesson.id}`);
|
||||
} else {
|
||||
goto(`/courses/${data.courseId}/lessons`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$: shouldGoToNextLesson = query.get('next') === 'true';
|
||||
$: shouldGoToNextLesson && onNextQuery($lessons);
|
||||
</script>
|
||||
|
||||
{#if $handleAddLessonWidget}
|
||||
@@ -94,7 +122,7 @@
|
||||
/>
|
||||
|
||||
<!-- TODO: Refactor usage of two way binding isStudent, rather use $globalStore.isStudent -->
|
||||
<CourseContainer bind:isStudent bind:courseId={data.courseId}>
|
||||
<CourseContainer bind:isFetching bind:isStudent bind:courseId={data.courseId}>
|
||||
<PageNav title="Lessons">
|
||||
<div slot="widget">
|
||||
<RoleBasedSecurity allowedRoles={[1, 2]}>
|
||||
@@ -104,7 +132,18 @@
|
||||
</PageNav>
|
||||
|
||||
<PageBody width="max-w-6xl" padding="p-0">
|
||||
{#if $lessons.length}
|
||||
{#if shouldGoToNextLesson}
|
||||
<Box className="w-full lg:w-11/12 lg:px-4 m-auto">
|
||||
<div class="flex flex-col items-center justify-between">
|
||||
<img src="/images/empty-lesson-icon.svg" alt="Lesson" class="mx-auto my-2.5" />
|
||||
<h2 class="my-1.5 text-xl font-normal">No lessons yet</h2>
|
||||
<p class="text-center text-sm text-slate-500">
|
||||
Share your knowledge with the world by creating engaging lessons. Start by clicking on
|
||||
the Add button.
|
||||
</p>
|
||||
</div>
|
||||
</Box>
|
||||
{:else if $lessons.length}
|
||||
<section
|
||||
class="m-auto w-full p-3 lg:w-11/12 lg:px-4"
|
||||
use:dndzone={{
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
import type { LessonCompletion } from '$lib/utils/types';
|
||||
import { profile } from '$lib/utils/store/user';
|
||||
import { getIsLessonComplete } from '$lib/components/Course/components/Lesson/functions';
|
||||
import { captureMessage } from '@sentry/browser';
|
||||
|
||||
export let data;
|
||||
|
||||
@@ -75,29 +76,38 @@
|
||||
}
|
||||
|
||||
async function markLessonComplete(lessonId: string) {
|
||||
let found = false;
|
||||
isMarkingComplete = true;
|
||||
|
||||
let completion: LessonCompletion = {
|
||||
let newCompletion: LessonCompletion = {
|
||||
is_complete: true,
|
||||
profile_id: $profile.id || '',
|
||||
lesson_id: lessonId,
|
||||
created_at: new Date().toDateString(),
|
||||
updated_at: new Date().toDateString()
|
||||
};
|
||||
const completions: LessonCompletion[] = $lesson.lesson_completion.map((_completion) => {
|
||||
if (_completion.profile_id === $profile.id) {
|
||||
found = true;
|
||||
let updatedCompletion: LessonCompletion;
|
||||
|
||||
const completions: LessonCompletion[] = $lesson.lesson_completion.map((completion) => {
|
||||
if (completion.profile_id === $profile.id) {
|
||||
console.log('shouldUpdate');
|
||||
|
||||
completion = {
|
||||
...completion,
|
||||
is_complete: _completion.is_complete
|
||||
is_complete: !completion.is_complete
|
||||
};
|
||||
|
||||
updatedCompletion = completion;
|
||||
}
|
||||
|
||||
return _completion;
|
||||
return completion;
|
||||
});
|
||||
if (!found) {
|
||||
completions.push(completion);
|
||||
|
||||
// @ts-ignore
|
||||
if (updatedCompletion) {
|
||||
await updateLessonCompletion(updatedCompletion, true);
|
||||
} else {
|
||||
completions.push(newCompletion);
|
||||
await updateLessonCompletion(newCompletion, false);
|
||||
}
|
||||
|
||||
$lesson.lesson_completion = completions;
|
||||
@@ -108,8 +118,6 @@
|
||||
|
||||
return l;
|
||||
});
|
||||
|
||||
await updateLessonCompletion(completion);
|
||||
snackbar.success('Marked as complete');
|
||||
isMarkingComplete = false;
|
||||
}
|
||||
|
||||
@@ -326,12 +326,6 @@ INSERT INTO "public"."lesson_comment" ("id", "created_at", "updated_at", "lesson
|
||||
-- Data for Name: lesson_completion; Type: TABLE DATA; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
INSERT INTO "public"."lesson_completion" ("id", "created_at", "lesson_id", "profile_id", "is_complete", "updated_at") VALUES
|
||||
(1, '2023-12-18 00:00:00+00', '5e5c8221-4c11-4c40-8664-11743bb79579', '0c256e75-aa40-4f62-8d30-0217ca1c60d9', true, '2023-12-18 00:00:00+00'),
|
||||
(2, '2023-12-18 00:00:00+00', '829da386-8ccd-4c81-b2fb-b9891102c83c', '0c256e75-aa40-4f62-8d30-0217ca1c60d9', true, '2023-12-18 00:00:00+00'),
|
||||
(3, '2023-12-19 00:00:00+00', '829da386-8ccd-4c81-b2fb-b9891102c83c', '0c256e75-aa40-4f62-8d30-0217ca1c60d9', true, '2023-12-19 00:00:00+00'),
|
||||
(4, '2023-12-19 00:00:00+00', '829da386-8ccd-4c81-b2fb-b9891102c83c', '0c256e75-aa40-4f62-8d30-0217ca1c60d9', true, '2023-12-19 00:00:00+00');
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: lesson_progress; Type: TABLE DATA; Schema: public; Owner: postgres
|
||||
|
||||
Reference in New Issue
Block a user