CLASSROOMIO-T-180: LMS dashboard improvements

This commit is contained in:
Rotimi Best
2023-09-29 09:25:32 +01:00
parent acfd01316f
commit 8777ab57f9
10 changed files with 69 additions and 208 deletions
@@ -17,8 +17,6 @@
export let isLMS = false;
export let progressRate = 45;
$: console.log(progressRate);
$: formatter = getCurrencyFormatter(currency);
</script>
+5 -1
View File
@@ -1,7 +1,10 @@
import { writable } from 'svelte/store';
import { writable, derived } from 'svelte/store';
import type { Course } from '$lib/utils/types';
export const courses = writable<Course[]>([]);
export const courseInProgress = derived(courses, ($courses) =>
$courses.length > 0 ? $courses.slice(0, 3) : []
);
export const courseMetaDeta = writable({
isLoading: true
});
@@ -23,4 +26,5 @@ export const copyCourseModalInitialState = {
isSaving: false,
error: null
};
export const copyCourseModal = writable({ ...copyCourseModalInitialState });
@@ -1,72 +0,0 @@
<script>
import { goto } from '$app/navigation';
import Box from '$lib/components/Box/index.svelte';
import CoursesEmptyIcon from '$lib/components/Icons/CoursesEmptyIcon.svelte';
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
import { courseCompleted } from './store';
const getCourse = () => {
goto(`/courses/${title}`);
};
</script>
<section>
{#if courseCompleted.length > 0}
<div
class="flex items-center justify-center md:justify-start flex-wrap gap-4 dark:text-white mt-2"
>
{#each courseCompleted as data}s
<div
class="w-80 min-h-[350px] flex items-start justify-start flex-col border rounded mr-2 mb-5 border-gray-200"
>
<div class="w-full h-[180px]">
<img src={data.src} alt="course" class="w-full h-full object-cover" />
</div>
<div class="w-full p-3">
<p
class="line-clamp-2 text-xl lg:text-2xl font-normal text-[#262626] dark:text-white py-1"
>
{data.title}
</p>
<p class="line-clamp-2 text-base text-[#656565] dark:text-white py-1">
{data.description}
</p>
<p class="py-1 text-[#7888B7] dark:text-white">By {data.author}</p>
<span
class="flex flex-col-reverse lg:flex-row items-start lg:items-center gap-2 justify-between"
>
<span>
<p>{data.lessons} lessons</p>
{#if data.inProgress}
<div class="flex items-center gap-2">
<div class=" relative bg-[#EAEAEA] w-full h-1">
<div
class={`absolute top-0 left-0 bg-primary-700 h-full ${data.progress} ]`}
/>
</div>
<p class="text-xs text-[#656565] dark:text-white">{data.progressRate}%</p>
</div>
{/if}
</span>
<PrimaryButton
label={data.inProgress ? 'Continue Course' : 'Start Course'}
variant={VARIANTS.OUTLINED}
className="rounded-none text-[#0233BD]"
onClick={getCourse}
/>
</span>
</div>
</div>
{/each}
</div>
{:else}
<Box className="flex flex-col items-center mt-2">
<CoursesEmptyIcon />
<h3 class="text-center">No courses completed yet</h3>
<p class="w-[70%] md:w-[35%] text-center">
Courses you complete will appear here. We believe in you , finish hard 💪🏾.
</p>
</Box>
{/if}
</section>
@@ -1,35 +0,0 @@
<script>
import Box from '$lib/components/Box/index.svelte';
import CoursesEmptyIcon from '$lib/components/Icons/CoursesEmptyIcon.svelte';
import { courseInProgress } from './store';
import Card from '$lib/components/Courses/components/Card/index.svelte';
</script>
<section>
{#if courseInProgress.length > 0}
<div
class="flex items-center justify-center md:justify-start flex-wrap gap-4 dark:text-white mt-2"
>
{#each courseInProgress as data}
{#key data.id}
<Card
id={data.id}
bannerImage={data.src || '/images/classroomio-course-img-template.jpg'}
title={data.title}
description={data.description}
isLMS={true}
progressRate={data.progressRate}
/>
{/key}
{/each}
</div>
{:else}
<Box className="flex flex-col items-center mt-2">
<CoursesEmptyIcon />
<h3 class="text-center">No course progress yet</h3>
<p class="w-[70%] md:w-[35%] text-center">
Once you start a course, your progress will reflect here
</p>
</Box>
{/if}
</section>
@@ -1,14 +1,13 @@
<script>
<script lang="ts">
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
import { goto } from '$app/navigation';
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
import { course } from '$lib/components/Course/store';
import Box from '$lib/components/Box/index.svelte';
import CoursesEmptyIcon from '$lib/components/Icons/CoursesEmptyIcon.svelte';
import { courseInProgress } from './store';
import { courseInProgress } from '$lib/components/Courses/store';
const gotoCourse = (title) => {
goto(`/courses/${title}`);
const gotoCourse = (id: string | undefined) => {
if (!id) return;
goto(`/courses/${id}`);
};
</script>
@@ -17,27 +16,34 @@
<div
class="flex items-center flex-col border border-[#EAEAEA] dark:bg-neutral-800 gap-2 rounded w-full h-fit xl:h-[516px] p-3"
>
{#if courseInProgress.length > 0}
{#if $courseInProgress.length > 0}
<div class="w-full h-full xl:h-[516px] flex flex-col justify-start">
{#each courseInProgress as data, index}
{#each $courseInProgress as course}
<div class="p-5">
<span class="flex flex-col md:flex-row gap-3 items-start pb-5">
<img src={data.src} alt="course" class="hidden md:block md:w-[60px] md:h-[60px]" />
<img
src={course.logo || '/images/classroomio-course-img-template.jpg'}
alt="course"
class="hidden md:block md:w-[60px] md:h-[60px]"
/>
<div class="w-full">
<p class="text-base font-semibold dark:text-white">{data.title}</p>
<p class="text-base font-semibold dark:text-white">{course.title}</p>
<p class="line-clamp-2 text-xs font-normal text-[#656565] dark:text-white">
{data.description}
{course.description}
</p>
</div>
<PrimaryButton
label="Continue"
variant={VARIANTS.OUTLINED}
className="rounded-none text-[#0233BD]"
onClick={() => gotoCourse(data.title)}
onClick={() => gotoCourse(course.id)}
/>
</span>
<div class="relative bg-[#EAEAEA] w-full h-1">
<div class={`absolute top-0 left-0 bg-primary-700 h-full ${data.progress} ]`} />
<div
style="width:{course.progress_rate}%"
class={`absolute top-0 left-0 bg-primary-700 h-full`}
/>
</div>
</div>
{/each}
@@ -45,7 +51,7 @@
{:else}
<div class="flex flex-col items-center">
<CoursesEmptyIcon />
<h3 class="text-center">No courses progress yet</h3>
<h3 class="text-center">No courses in progress yet</h3>
<p class="w-[75%] text-center">Once you start a course, your progress will reflect here</p>
</div>
{/if}
@@ -14,7 +14,6 @@
async function logout() {
const { error } = await supabase.auth.signOut();
console.log('error logout', error);
goto('/login');
}
@@ -23,8 +23,6 @@
}
}
};
// just copy and paste
</script>
<section class="w-full h-full mt-2">
@@ -1,45 +0,0 @@
export const mockData = [
{
id: '1',
title: 'Photo editing 101',
description:
'Learn the different techniques to edit photos using Adobe Lightroom.Learn the basics of figma and start design web apps for the world ...Learn the basics of figma and start design web apps for the world ...',
author: 'Derrick Amenuvue',
lessons: 8,
inProgress: true,
completed: false,
src: '/digital.svg',
progress: 'w-[45%]',
progressRate: 45
},
{
id: '2',
title: 'Colorful digital painting',
description:
'Learn the different techniques to edit photos using Adobe Lightroom.Learn the basics of figma and start design web apps for the world ...Learn the basics of figma and start design web apps for the world ...',
author: 'Derrick Amenuvue',
inProgress: true,
completed: false,
lessons: 5,
src: '/painting.svg',
progress: 'w-[30%]',
progressRate: 45
},
{
id: '3',
title: 'AI for dummys',
description:
'Learn the different techniques to edit photos using Adobe Lightroom.Learn the basics of figma and start design web apps for the world ...Learn the basics of figma and start design web apps for the world ...',
author: 'Derrick Amenuvue',
inProgress: false,
completed: false,
lessons: 18,
src: '/digital.svg',
progress: 'w-[45%]',
progressRate: 45
}
];
export const courseInProgress = mockData.filter((course) => course.inProgress);
export const courseCompleted = mockData.filter((course) => course.completed);
export const totalCourses = mockData.length;
export const progressPercentage = Math.round((courseInProgress.length / totalCourses) * 100);
+42 -11
View File
@@ -1,14 +1,45 @@
<script>
import Student from '$lib/components/LMS/components/Student.svelte';
<script lang="ts">
import Schedule from '$lib/components/LMS/components/Schedule.svelte';
import Learning from '$lib/components/LMS/components/Learning.svelte';
import {
courseInProgress,
totalCourses,
progressPercentage
} from '$lib/components/LMS/components/store';
import PrimaryButton from '$lib/components/PrimaryButton/index.svelte';
import { VARIANTS } from '$lib/components/PrimaryButton/constants';
import { goto } from '$app/navigation';
import { profile } from '$lib/utils/store/user';
import { fetchCourses } from '$lib/components/Courses/api';
import { currentOrg } from '$lib/utils/store/org';
import { courses, courseMetaDeta } from '$lib/components/Courses/store';
import type { Course } from '$lib/utils/types';
let hasFetched = false;
let progressPercentage = 0;
let totalLessons = 0;
let totalComPleted = 0;
async function getCourses(userId: string | null, orgId: string) {
if (hasFetched || !userId || !orgId) {
return;
}
$courseMetaDeta.isLoading = true;
const coursesResult = await fetchCourses(userId, orgId);
console.log(`coursesResult`, coursesResult);
$courseMetaDeta.isLoading = false;
if (!coursesResult) return;
courses.set(coursesResult.allCourses);
hasFetched = true;
}
function calcTotalProgress(courses: Course[]) {
totalComPleted = courses.reduce((acc, cur) => acc + (cur.progress_rate || 0), 0);
totalLessons = courses.reduce((acc, cur) => acc + (cur.total_lessons || 0), 0);
progressPercentage = Math.round((totalComPleted / totalLessons) * 100);
}
$: getCourses($profile.id, $currentOrg.id);
$: calcTotalProgress($courses);
</script>
<svelte:head>
@@ -41,7 +72,7 @@
</div>
<main class="flex w-full h-full flex-col xl:flex-row xl:gap-5">
<div class="w-full h-full">
<Student />
<Schedule />
</div>
<div class="w-full h-full">
@@ -58,12 +89,12 @@
</div>
<span class="text-center xl:text-start">
<p class="text-base font-semibold py-2 text-[#040F2D] dark:text-white">Your Progress</p>
{#if courseInProgress.length > 0}
{#if totalLessons > 0}
<p class="text-xs font-normal text-[#656565] dark:text-white">
{courseInProgress.length}/{totalCourses} lessons in progress
{totalComPleted}/{totalLessons} lessons completed
</p>
{:else}
<p class="text-xs font-normal text-[#656565] dark:text-white">No lessons started</p>
<p class="text-xs font-normal text-[#656565] dark:text-white">No courses started</p>
{/if}
</span>
<h1 class="text-5xl md:text-6xl font-bold text-[#262626] dark:text-white my-0">
+2 -25
View File
@@ -1,14 +1,9 @@
<script lang="ts">
import { Search } from 'carbon-components-svelte';
import Completed from '$lib/components/LMS/components/Completed.svelte';
import { courseInProgress } from '$lib/components/LMS/components/store';
import Tabs from '$lib/components/Tabs/index.svelte';
import TabContent from '$lib/components/TabContent/index.svelte';
import Courses from '$lib/components/Courses/index.svelte';
import { courses, courseMetaDeta } from '$lib/components/Courses/store';
import { profile } from '$lib/utils/store/user';
import { fetchCourses } from '$lib/components/Courses/api';
import { currentOrg } from '$lib/utils/store/org';
import { courses } from '$lib/components/Courses/store';
const tabs = [
{
@@ -21,29 +16,11 @@
}
];
let currentTab = tabs[0].value;
let hasFetched = false;
const onChange =
(tab = 0) =>
() =>
(currentTab = tab);
async function getCourses(userId: string | null, orgId: string) {
if (!hasFetched) {
$courseMetaDeta.isLoading = true;
const coursesResult = await fetchCourses(userId, orgId);
console.log(`coursesResult`, coursesResult);
$courseMetaDeta.isLoading = false;
if (!coursesResult) return;
courses.set(coursesResult.allCourses);
hasFetched = true;
}
}
$: getCourses($profile.id, $currentOrg.id);
</script>
<section class="max-w-6xl mx-auto">
@@ -58,7 +35,7 @@
<Courses courses={$courses} />
</TabContent>
<TabContent value={tabs[1].value} index={currentTab}>
<Completed />
<Courses courses={[]} />
</TabContent>
</slot:fragment>
</Tabs>