diff --git a/apps/dashboard/src/lib/features/course/components/card.svelte b/apps/dashboard/src/lib/features/course/components/card.svelte
index d4ab45e4..c77c9a6f 100644
--- a/apps/dashboard/src/lib/features/course/components/card.svelte
+++ b/apps/dashboard/src/lib/features/course/components/card.svelte
@@ -36,12 +36,13 @@
isOnLandingPage?: boolean;
isLMS?: boolean;
isExplore?: boolean;
+ isCertificateView?: boolean;
href?: string;
actions?: Snippet;
onExploreClick?: () => void;
}
- let { course, isOnLandingPage, isLMS, isExplore, href, actions, onExploreClick }: Props = $props();
+ let { course, isOnLandingPage, isLMS, isExplore, isCertificateView, href, actions, onExploreClick }: Props = $props();
let {
bannerImage,
@@ -150,6 +151,10 @@
return href;
}
+ if (isCertificateView) {
+ return `/courses/${id}/certificates`;
+ }
+
if (isOnLandingPage || isExplore) {
if (!slug) {
return undefined;
@@ -198,6 +203,9 @@
? getStudentCourseComplianceDate(course as UserEnrolledCourses[number])
: null
);
+ const certificateEarnedAt = $derived(
+ isCertificateView && 'certificateEarnedAt' in course ? course.certificateEarnedAt : null
+ );
function formatDate(value: string | null | undefined) {
if (!value) {
@@ -275,7 +283,13 @@
{/if}
{:else if isLMS}
- {#if !isExplore}
+ {#if isCertificateView}
+ {#if certificateEarnedAt}
+
+ {$t('certificates.earned_on')}: {formatDate(certificateEarnedAt)}
+
+ {/if}
+ {:else if !isExplore}
{progressRate}%
@@ -305,7 +319,11 @@
{#if isLMS}
diff --git a/apps/dashboard/src/lib/features/lms/pages/certificates.svelte b/apps/dashboard/src/lib/features/lms/pages/certificates.svelte
new file mode 100644
index 00000000..e73bba91
--- /dev/null
+++ b/apps/dashboard/src/lib/features/lms/pages/certificates.svelte
@@ -0,0 +1,70 @@
+
+
+
+
+
+ {#if coursesApi.isLoading}
+
+ {:else if filteredCertificates.length === 0}
+
+ {#if !searchValue.trim()}
+
+ {/if}
+
+ {:else}
+
+ {/if}
+
diff --git a/apps/dashboard/src/lib/features/lms/pages/index.ts b/apps/dashboard/src/lib/features/lms/pages/index.ts
index 61fdb684..ce2016c6 100644
--- a/apps/dashboard/src/lib/features/lms/pages/index.ts
+++ b/apps/dashboard/src/lib/features/lms/pages/index.ts
@@ -1,4 +1,5 @@
export { default as DashboardPage } from './dashboard.svelte';
export { default as ExplorePage } from './explore.svelte';
export { default as MyLearningPage } from './mylearning.svelte';
+export { default as CertificatesPage } from './certificates.svelte';
export { default as ExercisesPage } from './exercises.svelte';
diff --git a/apps/dashboard/src/lib/features/ui/navigation/lms-navigation.ts b/apps/dashboard/src/lib/features/ui/navigation/lms-navigation.ts
index d66b36d4..6e61b877 100644
--- a/apps/dashboard/src/lib/features/ui/navigation/lms-navigation.ts
+++ b/apps/dashboard/src/lib/features/ui/navigation/lms-navigation.ts
@@ -1,4 +1,5 @@
import {
+ CertificateIcon,
CommunityIcon,
CourseIcon,
ExerciseIcon,
@@ -11,6 +12,7 @@ import {
import type { AccountOrg } from '$features/app/types';
import type { Component } from 'svelte';
import { isActive } from '$lib/utils/functions/app';
+import { isOrgOnFreePlan } from '$lib/utils/store/org';
export interface NavItem {
title: string;
@@ -57,6 +59,13 @@ export const baseNavConfig: NavItemConfig[] = [
icon: CourseIcon,
matchPattern: '^/lms/mylearning(/.*)?$'
},
+ {
+ titleKey: 'lms_navigation.certificates',
+ path: '/certificates',
+ icon: CertificateIcon,
+ matchPattern: '^/lms/certificates(/.*)?$',
+ show: (currentOrg) => !isOrgOnFreePlan(currentOrg)
+ },
{
titleKey: 'lms_navigation.explore',
path: '/explore',
diff --git a/apps/dashboard/src/lib/utils/store/org.ts b/apps/dashboard/src/lib/utils/store/org.ts
index d26ad994..992ff0ef 100644
--- a/apps/dashboard/src/lib/utils/store/org.ts
+++ b/apps/dashboard/src/lib/utils/store/org.ts
@@ -71,6 +71,16 @@ const getActivePlan = (org: AccountOrg) => {
return org.plans.find((p) => p.isActive);
};
+export function isOrgOnFreePlan(org: AccountOrg | null | undefined) {
+ if (!org?.id || PUBLIC_IS_SELFHOSTED === 'true') {
+ return false;
+ }
+
+ const plan = getActivePlan(org);
+
+ return !plan || plan.planName === PLAN.BASIC;
+}
+
export const currentOrgPlan = derived(currentOrg, ($currentOrg) => getActivePlan($currentOrg));
export const currentOrgPath = derived(currentOrg, ($currentOrg) =>
@@ -126,13 +136,7 @@ export function getOrgPublicUrl(org: OrgPublicOrigin, pathname = '/'): string {
export const currentOrgDomain = derived(currentOrg, ($currentOrg) => getOrgPublicOrigin($currentOrg));
-export const isFreePlan = derived(currentOrg, ($currentOrg) => {
- if (!$currentOrg.id || PUBLIC_IS_SELFHOSTED === 'true') return false;
-
- const plan = getActivePlan($currentOrg);
-
- return !plan || plan.planName === PLAN.BASIC;
-});
+export const isFreePlan = derived(currentOrg, ($currentOrg) => isOrgOnFreePlan($currentOrg));
export const isEnterprisePlan = derived(currentOrg, ($currentOrg) => {
if (PUBLIC_IS_SELFHOSTED === 'true') return true;
diff --git a/apps/dashboard/src/lib/utils/translations/da.json b/apps/dashboard/src/lib/utils/translations/da.json
index 33118de2..0c6c531c 100644
--- a/apps/dashboard/src/lib/utils/translations/da.json
+++ b/apps/dashboard/src/lib/utils/translations/da.json
@@ -471,9 +471,22 @@
"any_course": "Ethvert kursus, du gennemfører, vil blive vist her",
"find_courses": "Find kurser"
},
+ "certificates": {
+ "heading": "Certifikater",
+ "description": "Se og download certifikater, du har opnået ved at gennemføre kurser.",
+ "search": "Søg certifikater",
+ "earned_on": "Opnået den",
+ "view_certificate": "Se certifikat",
+ "empty_title": "Ingen certifikater endnu",
+ "empty_description": "Gennemfør et kursus for at opnå dit første certifikat. Dine opnåede certifikater vises her.",
+ "no_results_title": "Ingen certifikater fundet",
+ "no_results_description": "Prøv et andet søgeord.",
+ "go_to_my_learning": "Gå til Min Læring"
+ },
"lms_navigation": {
"home": "Hjem",
"my_learning": "Min Læring",
+ "certificates": "Certifikater",
"exercise": "Motion",
"community": "Fællesskab",
"explore": "Udforsk",
diff --git a/apps/dashboard/src/lib/utils/translations/de.json b/apps/dashboard/src/lib/utils/translations/de.json
index ee467145..f9a4ff3b 100644
--- a/apps/dashboard/src/lib/utils/translations/de.json
+++ b/apps/dashboard/src/lib/utils/translations/de.json
@@ -471,9 +471,22 @@
"any_course": "Alle von Ihnen abgeschlossenen Kurse werden hier angezeigt",
"find_courses": "Kurse finden"
},
+ "certificates": {
+ "heading": "Zertifikate",
+ "description": "Sieh dir Zertifikate an und lade sie herunter, die du durch den Abschluss von Kursen erworben hast.",
+ "search": "Zertifikate suchen",
+ "earned_on": "Erworben am",
+ "view_certificate": "Zertifikat anzeigen",
+ "empty_title": "Noch keine Zertifikate",
+ "empty_description": "Schließe einen Kurs ab, um dein erstes Zertifikat zu verdienen. Deine erworbenen Zertifikate werden hier angezeigt.",
+ "no_results_title": "Keine Zertifikate gefunden",
+ "no_results_description": "Versuche einen anderen Suchbegriff.",
+ "go_to_my_learning": "Zu Mein Lernen"
+ },
"lms_navigation": {
"home": "Zuhause",
"my_learning": "Mein Lernen",
+ "certificates": "Zertifikate",
"exercise": "Übung",
"community": "Gemeinschaft",
"explore": "Entdecken",
diff --git a/apps/dashboard/src/lib/utils/translations/en.json b/apps/dashboard/src/lib/utils/translations/en.json
index 6d596402..aae52c0b 100644
--- a/apps/dashboard/src/lib/utils/translations/en.json
+++ b/apps/dashboard/src/lib/utils/translations/en.json
@@ -4059,6 +4059,7 @@
"lms_navigation": {
"home": "Home",
"my_learning": "My Learning",
+ "certificates": "Certificates",
"programs": "Programs",
"exercise": "Exercise",
"community": "Community",
@@ -4077,6 +4078,18 @@
"any_course": "Any course that you complete will be displayed here",
"find_courses": "Find courses"
},
+ "certificates": {
+ "heading": "Certificates",
+ "description": "View and download certificates you've earned by completing courses.",
+ "search": "Search certificates",
+ "earned_on": "Earned on",
+ "view_certificate": "View Certificate",
+ "empty_title": "No certificates yet",
+ "empty_description": "Complete a course to earn your first certificate. Your earned certificates will appear here.",
+ "no_results_title": "No certificates found",
+ "no_results_description": "Try a different search term.",
+ "go_to_my_learning": "Go to My Learning"
+ },
"exercises": {
"heading": "Exercises",
"not_submitted": "Not Submitted",
diff --git a/apps/dashboard/src/lib/utils/translations/es.json b/apps/dashboard/src/lib/utils/translations/es.json
index 2c83ca4e..0ace87e4 100644
--- a/apps/dashboard/src/lib/utils/translations/es.json
+++ b/apps/dashboard/src/lib/utils/translations/es.json
@@ -471,9 +471,22 @@
"any_course": "Cualquier curso que completes se mostrará aquí.",
"find_courses": "encontrar cursos"
},
+ "certificates": {
+ "heading": "Certificados",
+ "description": "Ve y descarga los certificados que has obtenido al completar cursos.",
+ "search": "Buscar certificados",
+ "earned_on": "Obtenido el",
+ "view_certificate": "Ver certificado",
+ "empty_title": "Aún no hay certificados",
+ "empty_description": "Completa un curso para obtener tu primer certificado. Tus certificados obtenidos aparecerán aquí.",
+ "no_results_title": "No se encontraron certificados",
+ "no_results_description": "Prueba con otro término de búsqueda.",
+ "go_to_my_learning": "Ir a Mi aprendizaje"
+ },
"lms_navigation": {
"home": "Inicio",
"my_learning": "Mi aprendizaje",
+ "certificates": "Certificados",
"exercise": "Ejercicio",
"community": "Comunidad",
"explore": "Explorar",
diff --git a/apps/dashboard/src/lib/utils/translations/fr.json b/apps/dashboard/src/lib/utils/translations/fr.json
index 652edc82..0504da8e 100644
--- a/apps/dashboard/src/lib/utils/translations/fr.json
+++ b/apps/dashboard/src/lib/utils/translations/fr.json
@@ -471,9 +471,22 @@
"any_course": "Tout cours que vous terminez sera affiché ici",
"find_courses": "Trouver des cours"
},
+ "certificates": {
+ "heading": "Certificats",
+ "description": "Consultez et téléchargez les certificats que vous avez obtenus en terminant des cours.",
+ "search": "Rechercher des certificats",
+ "earned_on": "Obtenu le",
+ "view_certificate": "Voir le certificat",
+ "empty_title": "Aucun certificat pour le moment",
+ "empty_description": "Terminez un cours pour obtenir votre premier certificat. Vos certificats obtenus apparaîtront ici.",
+ "no_results_title": "Aucun certificat trouvé",
+ "no_results_description": "Essayez un autre terme de recherche.",
+ "go_to_my_learning": "Aller à Mon apprentissage"
+ },
"lms_navigation": {
"home": "Accueil",
"my_learning": "Mon apprentissage",
+ "certificates": "Certificats",
"exercise": "Exercice",
"community": "Communauté",
"explore": "Explorer",
diff --git a/apps/dashboard/src/lib/utils/translations/hi.json b/apps/dashboard/src/lib/utils/translations/hi.json
index 75b3675e..f3f35dad 100644
--- a/apps/dashboard/src/lib/utils/translations/hi.json
+++ b/apps/dashboard/src/lib/utils/translations/hi.json
@@ -471,9 +471,22 @@
"any_course": "आपके द्वारा पूरा किया गया कोई भी पाठ्यक्रम यहां प्रदर्शित किया जाएगा",
"find_courses": "पाठ्यक्रम खोजें"
},
+ "certificates": {
+ "heading": "प्रमाणपत्र",
+ "description": "पाठ्यक्रम पूरे करने पर आपको मिले प्रमाणपत्र देखें और डाउनलोड करें।",
+ "search": "प्रमाणपत्र खोजें",
+ "earned_on": "प्राप्त तिथि",
+ "view_certificate": "प्रमाणपत्र देखें",
+ "empty_title": "अभी तक कोई प्रमाणपत्र नहीं",
+ "empty_description": "अपना पहला प्रमाणपत्र अर्जित करने के लिए एक पाठ्यक्रम पूरा करें। आपके अर्जित प्रमाणपत्र यहाँ दिखाई देंगे।",
+ "no_results_title": "कोई प्रमाणपत्र नहीं मिला",
+ "no_results_description": "कोई अलग खोज शब्द आज़माएँ।",
+ "go_to_my_learning": "मेरी सीख पर जाएँ"
+ },
"lms_navigation": {
"home": "घर",
"my_learning": "मेरी सीख",
+ "certificates": "प्रमाणपत्र",
"exercise": "व्यायाम",
"community": "समुदाय",
"explore": "अन्वेषण करें",
diff --git a/apps/dashboard/src/lib/utils/translations/pl.json b/apps/dashboard/src/lib/utils/translations/pl.json
index 6e407f72..78a2e24e 100644
--- a/apps/dashboard/src/lib/utils/translations/pl.json
+++ b/apps/dashboard/src/lib/utils/translations/pl.json
@@ -471,9 +471,22 @@
"any_course": "Tutaj wyświetli się każdy ukończony kurs",
"find_courses": "Znajdź kursy"
},
+ "certificates": {
+ "heading": "Certyfikaty",
+ "description": "Przeglądaj i pobieraj certyfikaty uzyskane po ukończeniu kursów.",
+ "search": "Szukaj certyfikatów",
+ "earned_on": "Uzyskano",
+ "view_certificate": "Zobacz certyfikat",
+ "empty_title": "Brak certyfikatów",
+ "empty_description": "Ukończ kurs, aby zdobyć swój pierwszy certyfikat. Uzyskane certyfikaty pojawią się tutaj.",
+ "no_results_title": "Nie znaleziono certyfikatów",
+ "no_results_description": "Spróbuj innego wyszukiwania.",
+ "go_to_my_learning": "Przejdź do Moja nauka"
+ },
"lms_navigation": {
"home": "Dom",
"my_learning": "Moja nauka",
+ "certificates": "Certyfikaty",
"exercise": "Ćwicz",
"community": "Społeczność",
"explore": "Eksploruj",
diff --git a/apps/dashboard/src/lib/utils/translations/pt.json b/apps/dashboard/src/lib/utils/translations/pt.json
index 4a2e3d8e..9b9be200 100644
--- a/apps/dashboard/src/lib/utils/translations/pt.json
+++ b/apps/dashboard/src/lib/utils/translations/pt.json
@@ -471,9 +471,22 @@
"any_course": "Qualquer curso que você concluir será exibido aqui",
"find_courses": "Encontre cursos"
},
+ "certificates": {
+ "heading": "Certificados",
+ "description": "Veja e baixe os certificados que você obteve ao concluir cursos.",
+ "search": "Pesquisar certificados",
+ "earned_on": "Obtido em",
+ "view_certificate": "Ver certificado",
+ "empty_title": "Nenhum certificado ainda",
+ "empty_description": "Conclua um curso para obter seu primeiro certificado. Seus certificados obtidos aparecerão aqui.",
+ "no_results_title": "Nenhum certificado encontrado",
+ "no_results_description": "Tente outro termo de pesquisa.",
+ "go_to_my_learning": "Ir para Meu aprendizado"
+ },
"lms_navigation": {
"home": "Página inicial",
"my_learning": "Meu aprendizado",
+ "certificates": "Certificados",
"exercise": "Exercício",
"community": "Comunidade",
"explore": "Explorar",
diff --git a/apps/dashboard/src/lib/utils/translations/ru.json b/apps/dashboard/src/lib/utils/translations/ru.json
index 0555f630..0513234e 100644
--- a/apps/dashboard/src/lib/utils/translations/ru.json
+++ b/apps/dashboard/src/lib/utils/translations/ru.json
@@ -471,9 +471,22 @@
"any_course": "Здесь будут отображаться все пройденные вами курсы.",
"find_courses": "Найти курсы"
},
+ "certificates": {
+ "heading": "Сертификаты",
+ "description": "Просматривайте и скачивайте сертификаты, полученные за завершение курсов.",
+ "search": "Поиск сертификатов",
+ "earned_on": "Получен",
+ "view_certificate": "Посмотреть сертификат",
+ "empty_title": "Пока нет сертификатов",
+ "empty_description": "Завершите курс, чтобы получить свой первый сертификат. Полученные сертификаты появятся здесь.",
+ "no_results_title": "Сертификаты не найдены",
+ "no_results_description": "Попробуйте другой поисковый запрос.",
+ "go_to_my_learning": "Перейти к Моему обучению"
+ },
"lms_navigation": {
"home": "Главная",
"my_learning": "Мое обучение",
+ "certificates": "Сертификаты",
"exercise": "Упражнение",
"community": "Сообщество",
"explore": "Исследуйте",
diff --git a/apps/dashboard/src/lib/utils/translations/vi.json b/apps/dashboard/src/lib/utils/translations/vi.json
index 0f873a22..080e5178 100644
--- a/apps/dashboard/src/lib/utils/translations/vi.json
+++ b/apps/dashboard/src/lib/utils/translations/vi.json
@@ -471,9 +471,22 @@
"any_course": "Bất kỳ khóa học nào bạn hoàn thành sẽ được hiển thị ở đây",
"find_courses": "Tìm khóa học"
},
+ "certificates": {
+ "heading": "Chứng chỉ",
+ "description": "Xem và tải xuống các chứng chỉ bạn đã đạt được khi hoàn thành khóa học.",
+ "search": "Tìm kiếm chứng chỉ",
+ "earned_on": "Đạt được vào",
+ "view_certificate": "Xem chứng chỉ",
+ "empty_title": "Chưa có chứng chỉ nào",
+ "empty_description": "Hoàn thành một khóa học để nhận chứng chỉ đầu tiên của bạn. Các chứng chỉ đã đạt được sẽ hiển thị tại đây.",
+ "no_results_title": "Không tìm thấy chứng chỉ",
+ "no_results_description": "Hãy thử một từ khóa tìm kiếm khác.",
+ "go_to_my_learning": "Đi tới Học tập của tôi"
+ },
"lms_navigation": {
"home": "Trang chủ",
"my_learning": "Học tập của tôi",
+ "certificates": "Chứng chỉ",
"exercise": "tập thể dục",
"community": "cộng đồng",
"explore": "Khám phá",
diff --git a/apps/dashboard/src/routes/(app)/lms/certificates/+page.svelte b/apps/dashboard/src/routes/(app)/lms/certificates/+page.svelte
new file mode 100644
index 00000000..35bd315b
--- /dev/null
+++ b/apps/dashboard/src/routes/(app)/lms/certificates/+page.svelte
@@ -0,0 +1,23 @@
+
+
+
+ Certificates - ClassroomIO
+
+
+
+
+
+ {$t('certificates.heading')}
+ {$t('certificates.description')}
+
+
+
+ {#snippet child()}
+
+ {/snippet}
+
+