CLASSROOMIO-T-168: Mark lesson as complete

This commit is contained in:
Rotimi Best
2023-09-26 11:23:54 +01:00
parent ccf34e362d
commit e16dc148b1
12 changed files with 147 additions and 68 deletions
+1 -1
View File
@@ -50,7 +50,7 @@
});
</script>
<div class={`root ${$apps.open ? 'open dark:bg-slate-800' : 'close dark:bg-slate-800'}`}>
<div class={`root ${$apps.open ? 'open dark:bg-black' : 'close dark:bg-black'}`}>
<div class={`apps`}>
<div class="lg:hidden">
<IconButton
+1 -4
View File
@@ -34,7 +34,7 @@
}
</script>
<div class="root w-full min-h-screen flex items-center justify-center">
<div class="app-background w-full min-h-screen flex items-center justify-center">
<div class="container border border-gray bg-white dark:bg-black">
<div class="flex items-center flex-col p-2 lg:px-8 lg:py-3">
{#if !showOnlyContent || showLogo}
@@ -93,9 +93,6 @@
</div>
<style>
.root {
background: radial-gradient(circle at 10% 20%, rgb(239, 246, 249) 0%, rgb(206, 239, 253) 90%);
}
.container {
width: 450px;
}
@@ -15,19 +15,20 @@
import { goto } from '$app/navigation';
export let openModal = false;
export let isStudent;
let errors = {};
export let isStudent = false;
let errors = {
title: ''
};
let lesson = {
id: null,
title: '',
profile: undefined,
call_url: undefined,
lesson_at: new Date(),
is_unlocked: false,
is_complete: false
is_unlocked: false
};
function getLessonOrder(id) {
function getLessonOrder(id = '') {
const index = $lessons.findIndex((lesson) => lesson.id === id);
if (index < 9) {
return '0' + (index + 1);
@@ -1,4 +1,6 @@
export function getUniqueValue(label) {
import type { LessonCompletion } from '$lib/utils/types';
export function getUniqueValue(label: string) {
return label.toLowerCase().replace(' ', '');
}
@@ -15,9 +17,16 @@ export function generateQuestion(questions) {
generatedQuestions.push({
...question,
name,
options,
options
});
}
return generatedQuestions;
}
export function getIsLessonComplete(completions: LessonCompletion[], profileId: string | null) {
if (!Array.isArray(completions)) return false;
return completions.find((c) => {
return c.is_complete && c.profile_id === profileId;
});
}
@@ -12,15 +12,16 @@ export const lessons: Writable<Lesson[]> = writable([]);
export const lesson = writable<LessonPage>({
id: null,
totalExercises: 0,
is_complete: false,
isSaving: false,
materials: {
note: '',
slide_url: '',
videos: []
},
exercises: []
exercises: [],
lesson_completion: []
});
export const isLessonDirty = writable(false);
export function handleAddLesson() {
@@ -33,8 +34,7 @@ export function handleAddLesson() {
// profile: undefined,
call_url: undefined,
lesson_at: new Date(),
is_unlocked: false,
is_complete: false
is_unlocked: false
}
];
}) as Updater<any>);
@@ -60,12 +60,11 @@ export async function handleSaveLesson(lesson: Lesson, course_id: Course['id'])
console.log(`handleSaveLesson lesson`, lesson);
const newLesson = {
title: lesson.title,
lesson_at: lesson.lesson_at,
call_url: lesson.call_url,
teacher_id: lesson.profile ? lesson.profile.id : undefined,
lesson_at: lesson?.lesson_at,
call_url: lesson?.call_url,
teacher_id: lesson?.profile ? lesson?.profile.id : undefined,
course_id,
is_unlocked: lesson.is_unlocked,
is_complete: lesson.is_complete
is_unlocked: lesson.is_unlocked
};
let newLessonData: any[] | null = null;
@@ -85,7 +84,7 @@ export async function handleUpdateLessonMaterials(lesson: any, lessonId: Lesson[
const materials = {
...lesson.materials
};
delete materials.lesson_completion;
delete materials.profile;
delete materials.totalExercises;
@@ -1,4 +1,4 @@
<script>
<script lang="ts">
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import { page } from '$app/stores';
@@ -11,40 +11,40 @@
import TextChip from '$lib/components/Chip/Text.svelte';
import { lessons } from '../Lesson/store/lessons';
import { course } from '$lib/components/Course/store';
import { updateCourse } from '$lib/utils/services/courses';
import { NavClasses } from '$lib/utils/constants/reusableClass';
import { isMobile } from '$lib/utils/store/useMobile';
import { menu } from '$lib/components/Org/store';
import { profile } from '$lib/utils/store/user';
import { getIsLessonComplete } from '../Lesson/functions';
export let path;
export let isStudent = null;
export let path: string;
export let isStudent: boolean = false;
let show = null;
interface NavItem {
label: string;
to: string;
hideSortIcon: boolean;
isLecture?: boolean;
show?: () => boolean;
}
let show: boolean = false;
let isLessonActive = false;
const toggleSidebar = () => {
$menu.hidden = !$menu.hidden;
};
function handleMainGroupClick(href) {
function handleMainGroupClick(href: string) {
return () => {
goto(href);
toggleSidebar();
};
}
let navItems = [];
let navItems: NavItem[] = [];
function getHref(item) {
return item.to;
// return item.is_unlocked ? item.to : path || $page.url.pathname
}
function handleSaveTitle() {
updateCourse($course.id, { title: $course.title });
}
function handleMobileChange(isMobile) {
function handleMobileChange(isMobile: boolean) {
if (isMobile) show = false;
else show = true;
}
@@ -192,7 +192,7 @@
<span class="text-md ml-2" title="This lesson is locked.">
<LockedIcon class="carbon-icon dark:text-white" />
</span>
{:else if item.is_complete}
{:else if getIsLessonComplete(item.lesson_completion, $profile.id)}
<span class="ml-2" title="You have completed this lesson">
<CheckmarkFilled class="carbon-icon dark:text-white" />
</span>
+10 -8
View File
@@ -58,14 +58,16 @@
</li>
{#if isCoursePage}
<IconButton
onClick={() => {
goto(`${$currentOrgPath}/courses`);
}}
size="small"
>
<CourseIcon color="#fff" />
</IconButton>
<div class="hidden md:block">
<IconButton
onClick={() => {
goto(`${$currentOrgPath}/courses`);
}}
size="small"
>
<CourseIcon color="#fff" />
</IconButton>
</div>
{/if}
<a
href={getPathName(isCoursePage, $course.slug)}
+1 -1
View File
@@ -10,7 +10,7 @@
export let logo;
export let orgName;
export let isOrgSite = false;
export let backgroundColor = 'bg-white';
export let backgroundColor = 'bg-white dark:bg-black';
let navClass = '';
+18 -4
View File
@@ -1,7 +1,14 @@
import { supabase } from '$lib/utils/functions/supabase';
import { isUUID } from '$lib/utils/functions/isUUID';
import { QUESTION_TYPE } from '$lib/components/Question/constants';
import type { Lesson, Course, Group, Groupmember, Exercise } from '$lib/utils/types';
import type {
Lesson,
Course,
Group,
Groupmember,
Exercise,
LessonCompletion
} from '$lib/utils/types';
import { STATUS } from '$lib/utils/constants/course';
export async function fetchCourse(courseId?: Course['id'], slug?: Course['slug']) {
@@ -36,9 +43,10 @@ export async function fetchCourse(courseId?: Course['id'], slug?: Course['slug']
is_certificate_downloadable,
certificate_theme,
lessons:lesson(
id, title,public, lesson_at, call_url, is_unlocked, is_complete, order, created_at,
id, title,public, lesson_at, call_url, is_unlocked, order, created_at,
note, videos, slide_url, call_url, totalExercises:exercise(count),
profile:teacher_id(id, avatar_url, fullname)
profile:teacher_id(id, avatar_url, fullname),
lesson_completion(id, profile_id, is_complete)
),
attendance:group_attendance(*)
`
@@ -138,7 +146,9 @@ export function deleteGroupMember(groupMemberId: Groupmember['id']) {
export function fetchLesson(lessonId: Lesson['id']) {
return supabase
.from('lesson')
.select(`id, note, videos, slide_url, call_url, totalExercises:exercise(count)`)
.select(
`id, note, videos, slide_url, call_url, totalExercises:exercise(count), lesson_completion(id, profile_id, is_complete)`
)
.eq('id', lessonId)
.single();
}
@@ -154,6 +164,10 @@ 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 deleteLesson(lessonId: Lesson['id']) {
// Need to implement soft delete
return supabase.from('lesson').delete().match({ id: lessonId });
+15 -5
View File
@@ -143,14 +143,14 @@ export interface Group_attendance {
groupmember?: Groupmember;
}
enum VideoType {
export enum VideoType {
youtube,
muse
}
export interface LessonPage {
id?: string | null;
totalExercises: Number;
is_complete: Boolean;
isSaving: Boolean;
materials: {
note: string;
@@ -162,6 +162,16 @@ export interface LessonPage {
}>;
};
exercises: [];
lesson_completion: LessonCompletion[];
}
export interface LessonCompletion {
id?: number;
lesson_id: string;
profile_id: string;
is_complete: boolean;
created_at: string;
updated_at: string;
}
export interface Lesson {
@@ -169,19 +179,19 @@ export interface Lesson {
videos?: []; // type unknown;
slide_url?: any; // type unknown;
course_id: string /* foreign key to course.id */;
id?: string /* primary key */;
id: string /* primary key */;
created_at?: string;
updated_at?: string;
title: any; // type unknown;
title: string; // type unknown;
public?: boolean;
lesson_at?: string;
teacher_id?: string /* foreign key to profile.id */;
is_unlocked?: boolean;
is_complete?: boolean;
call_url?: string;
order?: number;
course?: Course;
profile?: Profile;
lesson_completion: LessonCompletion[];
}
export interface Exercise {