From 23a9b0154cbeb3b202ec31d88516732f4bb2a594 Mon Sep 17 00:00:00 2001 From: Marty Byrde <45905689+Marty-Byrde@users.noreply.github.com> Date: Fri, 27 Mar 2026 08:17:19 +0100 Subject: [PATCH 1/8] ref: moved examination result pages into `[locale]/results/` The reason for this change is that this way the `/courses` route directory is less cluttered is less cluttered but also viewing said results does not require share-token. Hence, users can view the results of a given check even after the respective share-token has been deleted. --- .../[courseId]/exam}/[attemptId]/page.tsx | 10 +++++----- .../results => results/[courseId]/exam}/page.tsx | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) rename src/app/[locale]/{courses/[share_token]/results => results/[courseId]/exam}/[attemptId]/page.tsx (74%) rename src/app/[locale]/{courses/[share_token]/results => results/[courseId]/exam}/page.tsx (95%) diff --git a/src/app/[locale]/courses/[share_token]/results/[attemptId]/page.tsx b/src/app/[locale]/results/[courseId]/exam/[attemptId]/page.tsx similarity index 74% rename from src/app/[locale]/courses/[share_token]/results/[attemptId]/page.tsx rename to src/app/[locale]/results/[courseId]/exam/[attemptId]/page.tsx index 34e639fa..e4e423ec 100644 --- a/src/app/[locale]/courses/[share_token]/results/[attemptId]/page.tsx +++ b/src/app/[locale]/results/[courseId]/exam/[attemptId]/page.tsx @@ -1,20 +1,20 @@ import { forbidden, notFound } from 'next/navigation' -import { getCourseByShareToken } from '@/database/course/select' +import { getCourseById } from '@/database/course/select' import { getExaminationAttemptById } from '@/database/examination/select' import { QuestionScoresLineChart } from '@/src/components/charts/QuestionScoresLineChart' +import ExamQuestionResultTable from '@/src/components/courses/[share_token]/results/ExamQuestionResultTable' import PageHeading from '@/src/components/Shared/PageHeading' import { getScopedI18n } from '@/src/i18n/server-localization' import requireAuthentication from '@/src/lib/auth/requireAuthentication' import hasCollaborativePermissions from '@/src/lib/courses/hasCollaborativePermissions' import getDummyExamAttempts from '@/src/lib/dummy/getDummyExamAttempts' -import ExamQuestionResultTable from '../../../../../../components/courses/[share_token]/results/ExamQuestionResultTable' -export default async function ExamAttemptResultPage({ params }: { params: Promise<{ share_token: string; attemptId: string }> }) { +export default async function ExamAttemptResultPage({ params }: { params: Promise<{ courseId: string; attemptId: string }> }) { const t = await getScopedI18n('Courses.ExaminatonResults.ExamAttemptResultPage') - const { share_token, attemptId } = await params + const { courseId, attemptId } = await params const { user } = await requireAuthentication() - let [course, attempt] = await Promise.all([getCourseByShareToken(share_token), getExaminationAttemptById(parseInt(attemptId))]) + let [course, attempt] = await Promise.all([getCourseById(courseId), getExaminationAttemptById(parseInt(attemptId))]) // dummy examinationAttempt data when a given attempt does not exist if (!attempt) attempt = (await getDummyExamAttempts(1))[0] diff --git a/src/app/[locale]/courses/[share_token]/results/page.tsx b/src/app/[locale]/results/[courseId]/exam/page.tsx similarity index 95% rename from src/app/[locale]/courses/[share_token]/results/page.tsx rename to src/app/[locale]/results/[courseId]/exam/page.tsx index dc27ba45..d034a41e 100644 --- a/src/app/[locale]/courses/[share_token]/results/page.tsx +++ b/src/app/[locale]/results/[courseId]/exam/page.tsx @@ -1,7 +1,7 @@ 'use server' import { forbidden, notFound } from 'next/navigation' -import { getCourseByShareToken } from '@/database/course/select' +import { getCourseById } from '@/database/course/select' import { getCourseExaminationAttempts } from '@/database/examination/select' import { ExaminationSuccessPieChart } from '@/src/components/charts/ExaminationSuccessPieChart' import { ExamQuestionDurationChart } from '@/src/components/charts/QuestionDurationChart' @@ -24,11 +24,11 @@ export type ExaminationAttemptTableStructure = Pick }) { - const { share_token } = await params +export default async function ExaminationResultsPage({ params }: { params: Promise<{ courseId: string }> }) { + const { courseId } = await params const { user } = await requireAuthentication() - const course = await getCourseByShareToken(share_token) + const course = await getCourseById(courseId) if (!course) notFound() if (!hasCollaborativePermissions(course, user.id)) forbidden() From f6eb13298be25c1661876f314aaebb4d584667f6 Mon Sep 17 00:00:00 2001 From: Marty Byrde <45905689+Marty-Byrde@users.noreply.github.com> Date: Fri, 27 Mar 2026 08:19:43 +0100 Subject: [PATCH 2/8] ref: mimiced exam results page structure to components This commits moves the exam results component into the same hierarchical structure as the exam-results page (`results/[courseId]/examination`) are so that they are easier to locate. --- src/app/[locale]/results/[courseId]/exam/[attemptId]/page.tsx | 2 +- .../courses/[share_token]/ExaminationAttemptTable.tsx | 2 +- .../examination}/ExamQuestionResultTable.tsx | 4 ++-- .../examination}/ExamQuestionTable_ActionMenu.tsx | 4 ++-- .../examination}/PreviewQuestionResultDrawer.tsx | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) rename src/components/{courses/[share_token]/results => results/examination}/ExamQuestionResultTable.tsx (96%) rename src/components/{courses/[share_token]/results => results/examination}/ExamQuestionTable_ActionMenu.tsx (91%) rename src/components/{courses/[share_token]/results => results/examination}/PreviewQuestionResultDrawer.tsx (99%) diff --git a/src/app/[locale]/results/[courseId]/exam/[attemptId]/page.tsx b/src/app/[locale]/results/[courseId]/exam/[attemptId]/page.tsx index e4e423ec..305c4511 100644 --- a/src/app/[locale]/results/[courseId]/exam/[attemptId]/page.tsx +++ b/src/app/[locale]/results/[courseId]/exam/[attemptId]/page.tsx @@ -2,7 +2,7 @@ import { forbidden, notFound } from 'next/navigation' import { getCourseById } from '@/database/course/select' import { getExaminationAttemptById } from '@/database/examination/select' import { QuestionScoresLineChart } from '@/src/components/charts/QuestionScoresLineChart' -import ExamQuestionResultTable from '@/src/components/courses/[share_token]/results/ExamQuestionResultTable' +import ExamQuestionResultTable from '@/src/components/results/examination/ExamQuestionResultTable' import PageHeading from '@/src/components/Shared/PageHeading' import { getScopedI18n } from '@/src/i18n/server-localization' import requireAuthentication from '@/src/lib/auth/requireAuthentication' diff --git a/src/components/courses/[share_token]/ExaminationAttemptTable.tsx b/src/components/courses/[share_token]/ExaminationAttemptTable.tsx index c5b979e0..3c9a96e5 100644 --- a/src/components/courses/[share_token]/ExaminationAttemptTable.tsx +++ b/src/components/courses/[share_token]/ExaminationAttemptTable.tsx @@ -157,7 +157,7 @@ export function ExaminationAttemptTable({ data: initialData }: { data: ExamAttem - + {t('columns.actions_menu.show_results_label')} diff --git a/src/components/courses/[share_token]/results/ExamQuestionResultTable.tsx b/src/components/results/examination/ExamQuestionResultTable.tsx similarity index 96% rename from src/components/courses/[share_token]/results/ExamQuestionResultTable.tsx rename to src/components/results/examination/ExamQuestionResultTable.tsx index 9c24f079..26c73f3f 100644 --- a/src/components/courses/[share_token]/results/ExamQuestionResultTable.tsx +++ b/src/components/results/examination/ExamQuestionResultTable.tsx @@ -3,8 +3,8 @@ import { IconCircleCheckFilled } from '@tabler/icons-react' import { ColumnDef } from '@tanstack/react-table' import { EyeIcon, XIcon } from 'lucide-react' -import ExamQuestionTable_ActionMenu from '@/src/components/courses/[share_token]/results/ExamQuestionTable_ActionMenu' -import ShowAnswerDrawer_TableCell from '@/src/components/courses/[share_token]/results/PreviewQuestionResultDrawer' +import ExamQuestionTable_ActionMenu from '@/src/components/results/examination/ExamQuestionTable_ActionMenu' +import ShowAnswerDrawer_TableCell from '@/src/components/results/examination/PreviewQuestionResultDrawer' import { Badge } from '@/src/components/shadcn/badge' import { Button } from '@/src/components/shadcn/button' import { Checkbox } from '@/src/components/shadcn/checkbox' diff --git a/src/components/courses/[share_token]/results/ExamQuestionTable_ActionMenu.tsx b/src/components/results/examination/ExamQuestionTable_ActionMenu.tsx similarity index 91% rename from src/components/courses/[share_token]/results/ExamQuestionTable_ActionMenu.tsx rename to src/components/results/examination/ExamQuestionTable_ActionMenu.tsx index 08b3b56c..458cf2e3 100644 --- a/src/components/courses/[share_token]/results/ExamQuestionTable_ActionMenu.tsx +++ b/src/components/results/examination/ExamQuestionTable_ActionMenu.tsx @@ -2,8 +2,8 @@ import { useState } from 'react' import { IconDotsVertical } from '@tabler/icons-react' import { Row } from '@tanstack/react-table' import { ChartColumnIcon, TrashIcon } from 'lucide-react' -import { PreviewQuestionResult_QuestionItem } from '@/src/components/courses/[share_token]/results/ExamQuestionResultTable' -import ShowAnswerDrawer_TableCell from '@/src/components/courses/[share_token]/results/PreviewQuestionResultDrawer' +import { PreviewQuestionResult_QuestionItem } from '@/src/components/results/examination/ExamQuestionResultTable' +import ShowAnswerDrawer_TableCell from '@/src/components/results/examination/PreviewQuestionResultDrawer' import { Button } from '@/src/components/shadcn/button' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from '@/src/components/shadcn/dropdown-menu' import { useCurrentLocale, useScopedI18n } from '@/src/i18n/client-localization' diff --git a/src/components/courses/[share_token]/results/PreviewQuestionResultDrawer.tsx b/src/components/results/examination/PreviewQuestionResultDrawer.tsx similarity index 99% rename from src/components/courses/[share_token]/results/PreviewQuestionResultDrawer.tsx rename to src/components/results/examination/PreviewQuestionResultDrawer.tsx index 496169df..da8d351c 100644 --- a/src/components/courses/[share_token]/results/PreviewQuestionResultDrawer.tsx +++ b/src/components/results/examination/PreviewQuestionResultDrawer.tsx @@ -3,7 +3,7 @@ import React, { Dispatch, SetStateAction, useState } from 'react' import { ChevronRightIcon, UserCheckIcon, UserIcon } from 'lucide-react' import { QuestionScoresLineChart } from '@/src/components/charts/QuestionScoresLineChart' -import { PreviewQuestionResult_QuestionItem } from '@/src/components/courses/[share_token]/results/ExamQuestionResultTable' +import { PreviewQuestionResult_QuestionItem } from '@/src/components/results/examination/ExamQuestionResultTable' import { Button } from '@/src/components/shadcn/button' import { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger } from '@/src/components/shadcn/drawer' import { Input } from '@/src/components/shadcn/input' From a37b56526fb29a0596d5f3ea77d0813f73e29f84 Mon Sep 17 00:00:00 2001 From: Marty Byrde <45905689+Marty-Byrde@users.noreply.github.com> Date: Fri, 27 Mar 2026 12:38:07 +0100 Subject: [PATCH 3/8] feat: added show exam results to `CourseActionMenu` This way users can now view examination results by clicking on the newly introduced menu-item within the `CourseActionMenu`. --- .../courses/(hamburger-menu)/CourseActionMenu.tsx | 9 ++++++++- src/i18n/locales/de.json | 3 +++ src/i18n/locales/de.ts | 3 +++ src/i18n/locales/en.json | 3 +++ src/i18n/locales/en.ts | 3 +++ 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/components/courses/(hamburger-menu)/CourseActionMenu.tsx b/src/components/courses/(hamburger-menu)/CourseActionMenu.tsx index 6af27250..c22682f9 100644 --- a/src/components/courses/(hamburger-menu)/CourseActionMenu.tsx +++ b/src/components/courses/(hamburger-menu)/CourseActionMenu.tsx @@ -1,7 +1,7 @@ 'use client' import { useState } from 'react' -import { ArrowUpRightIcon, CopyPlusIcon, EllipsisIcon, Share2Icon, SquarePenIcon, TrashIcon } from 'lucide-react' +import { ArrowUpRightIcon, ChartSplineIcon, CopyPlusIcon, EllipsisIcon, Share2Icon, SquarePenIcon, TrashIcon } from 'lucide-react' import Link from 'next/link' import { useRouter } from 'next/navigation' import { toast } from 'react-toastify' @@ -142,6 +142,13 @@ export default function CourseActionMenu({ id, questions, share_key, owner_id, c + + + + {t('show_exam_results.label')} + + + {t('clone_course.label')} diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index c80dd818..5b4a213c 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -421,6 +421,9 @@ "clone_course": { "label": "Kurs duplizieren" }, + "show_exam_results": { + "label": "Prüfungs Ergebnisse" + }, "inspect_statistics": { "label": "Statistik anzeigen" }, diff --git a/src/i18n/locales/de.ts b/src/i18n/locales/de.ts index ff514c09..208e23eb 100644 --- a/src/i18n/locales/de.ts +++ b/src/i18n/locales/de.ts @@ -425,6 +425,9 @@ export default { clone_course: { label: 'Kurs duplizieren' }, + show_exam_results: { + label: 'Prüfungs Ergebnisse' + }, inspect_statistics: { label: 'Statistik anzeigen' }, diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index e39d762c..133e29d8 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -430,6 +430,9 @@ "clone_course": { "label": "Clone Course" }, + "show_exam_results": { + "label": "Show Examination Results" + }, "inspect_statistics": { "label": "Inspect Statistics" }, diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index c434aa3a..d82c17eb 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -431,6 +431,9 @@ export default { clone_course: { label: 'Clone Course' }, + show_exam_results: { + label: 'Show Examination Results' + }, inspect_statistics: { label: 'Inspect Statistics' }, From 4b05f64654759b04425b47f4dfea1e2d8b1fe4f8 Mon Sep 17 00:00:00 2001 From: Marty Byrde <45905689+Marty-Byrde@users.noreply.github.com> Date: Sat, 28 Mar 2026 07:13:11 +0100 Subject: [PATCH 4/8] feat: added examination results breadcrumb components This way custom breadcrumbs are shown for both the examination results overview page and the individual attempt results page. The reason for this is that the `GenericBreadcrumbs` show dynamic route parameters like `courseId` in its Breadcrumbs, which is not necessarily good from a user perspective. --- .../examination/ExamResultsBreadcrumbs.tsx | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/components/results/examination/ExamResultsBreadcrumbs.tsx diff --git a/src/components/results/examination/ExamResultsBreadcrumbs.tsx b/src/components/results/examination/ExamResultsBreadcrumbs.tsx new file mode 100644 index 00000000..7a83a8f0 --- /dev/null +++ b/src/components/results/examination/ExamResultsBreadcrumbs.tsx @@ -0,0 +1,71 @@ +import { DetailedHTMLProps, HTMLAttributes } from 'react' +import Link from 'next/link' +import { getCourseById } from '@/database/course/select' +import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from '@/src/components/shadcn/breadcrumb' +import { Course } from '@/src/schemas/CourseSchema' + +function BaseBreadcrumbs({ + courseName, + courseId, + children, + ...props +}: { children: React.ReactNode; courseId: Course['id']; courseName: Course['name'] } & DetailedHTMLProps, HTMLElement>) { + return ( + + + + + Home + + + + + + Courses + + + + + + {courseName} + + + + {children} + + + ) +} + +export async function ExamResultsBreadcrumbs({ courseId, ...props }: { courseId: string } & DetailedHTMLProps, HTMLElement>) { + const course = await getCourseById(courseId) + if (!course) return null + + return ( + + + Examination Results + + + ) +} + +export async function ExamResultAttemptResultsBreadcrumbs({ courseId, userName, ...props }: { courseId: string; userName: string } & DetailedHTMLProps, HTMLElement>) { + const course = await getCourseById(courseId) + if (!course) return null + + return ( + + + + Examination Results + + + + + + {userName}'s Results + + + ) +} From 45a1ff6c8754f677909c73e2776f767a71dd1c73 Mon Sep 17 00:00:00 2001 From: Marty Byrde <45905689+Marty-Byrde@users.noreply.github.com> Date: Sat, 28 Mar 2026 07:13:43 +0100 Subject: [PATCH 5/8] ref: applied breadcrumbs to exam result pages --- src/app/[locale]/results/[courseId]/exam/[attemptId]/page.tsx | 2 ++ src/app/[locale]/results/[courseId]/exam/page.tsx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/app/[locale]/results/[courseId]/exam/[attemptId]/page.tsx b/src/app/[locale]/results/[courseId]/exam/[attemptId]/page.tsx index 305c4511..93e0e29b 100644 --- a/src/app/[locale]/results/[courseId]/exam/[attemptId]/page.tsx +++ b/src/app/[locale]/results/[courseId]/exam/[attemptId]/page.tsx @@ -3,6 +3,7 @@ import { getCourseById } from '@/database/course/select' import { getExaminationAttemptById } from '@/database/examination/select' import { QuestionScoresLineChart } from '@/src/components/charts/QuestionScoresLineChart' import ExamQuestionResultTable from '@/src/components/results/examination/ExamQuestionResultTable' +import { ExamResultAttemptResultsBreadcrumbs } from '@/src/components/results/examination/ExamResultsBreadcrumbs' import PageHeading from '@/src/components/Shared/PageHeading' import { getScopedI18n } from '@/src/i18n/server-localization' import requireAuthentication from '@/src/lib/auth/requireAuthentication' @@ -24,6 +25,7 @@ export default async function ExamAttemptResultPage({ params }: { params: Promis return ( <> +
diff --git a/src/app/[locale]/results/[courseId]/exam/page.tsx b/src/app/[locale]/results/[courseId]/exam/page.tsx index d034a41e..b30508b9 100644 --- a/src/app/[locale]/results/[courseId]/exam/page.tsx +++ b/src/app/[locale]/results/[courseId]/exam/page.tsx @@ -8,6 +8,7 @@ import { ExamQuestionDurationChart } from '@/src/components/charts/QuestionDurat import { QuestionScoresLineChartCard } from '@/src/components/charts/QuestionScoresLineChart' import { UserTypePieChart } from '@/src/components/charts/UserTypePieChart' import { ExaminationAttemptTable } from '@/src/components/courses/[share_token]/ExaminationAttemptTable' +import { ExamResultsBreadcrumbs } from '@/src/components/results/examination/ExamResultsBreadcrumbs' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/src/components/shadcn/card' import PageHeading from '@/src/components/Shared/PageHeading' import { getScopedI18n } from '@/src/i18n/server-localization' @@ -38,6 +39,7 @@ export default async function ExaminationResultsPage({ params }: { params: Promi return ( <> +
From 286e6545227f1804f5af418cf63c0133d8db6ce8 Mon Sep 17 00:00:00 2001 From: Marty Byrde <45905689+Marty-Byrde@users.noreply.github.com> Date: Sat, 28 Mar 2026 07:31:42 +0100 Subject: [PATCH 6/8] ref: localized new exam breadcrumbs texts --- .../examination/ExamResultsBreadcrumbs.tsx | 20 +++++++++++++------ src/i18n/locales/de.json | 18 ++++++++++++++++- src/i18n/locales/de.ts | 18 ++++++++++++++++- src/i18n/locales/en.json | 19 +++++++++++++++++- src/i18n/locales/en.ts | 18 ++++++++++++++++- 5 files changed, 83 insertions(+), 10 deletions(-) diff --git a/src/components/results/examination/ExamResultsBreadcrumbs.tsx b/src/components/results/examination/ExamResultsBreadcrumbs.tsx index 7a83a8f0..6462d0b9 100644 --- a/src/components/results/examination/ExamResultsBreadcrumbs.tsx +++ b/src/components/results/examination/ExamResultsBreadcrumbs.tsx @@ -1,27 +1,31 @@ +'use server' + import { DetailedHTMLProps, HTMLAttributes } from 'react' import Link from 'next/link' import { getCourseById } from '@/database/course/select' import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from '@/src/components/shadcn/breadcrumb' +import { getScopedI18n } from '@/src/i18n/server-localization' import { Course } from '@/src/schemas/CourseSchema' -function BaseBreadcrumbs({ +async function BaseBreadcrumbs({ courseName, courseId, children, ...props }: { children: React.ReactNode; courseId: Course['id']; courseName: Course['name'] } & DetailedHTMLProps, HTMLElement>) { + const t = await getScopedI18n('Shared.Breadcrumbs') return ( - Home + {t('root')} - Courses + {t('courses')} @@ -38,19 +42,21 @@ function BaseBreadcrumbs({ } export async function ExamResultsBreadcrumbs({ courseId, ...props }: { courseId: string } & DetailedHTMLProps, HTMLElement>) { + const t = await getScopedI18n('Shared.Breadcrumbs') const course = await getCourseById(courseId) if (!course) return null return ( - Examination Results + {t('examination_results')} ) } export async function ExamResultAttemptResultsBreadcrumbs({ courseId, userName, ...props }: { courseId: string; userName: string } & DetailedHTMLProps, HTMLElement>) { + const t = await getScopedI18n('Shared.Breadcrumbs') const course = await getCourseById(courseId) if (!course) return null @@ -58,13 +64,15 @@ export async function ExamResultAttemptResultsBreadcrumbs({ courseId, userName, - Examination Results + {t('examination_results')} - {userName}'s Results + + {userName}'s {t('results')} + ) diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 5b4a213c..8bbd235c 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -38,7 +38,23 @@ "minute_label#other": "minuten", "minute_label": "minuten" }, - "jump_back_button_label": "Bearbeiten" + "jump_back_button_label": "Bearbeiten", + "Breadcrumbs": { + "root": "Home", + "courses": "Kurse", + "discover": "Entdecken", + "practice": "Üben", + "edit": "Bearbeiten", + "create": "Erstellen", + "account": "Account", + "start": "Start", + "results": "Ergebnisse", + "examination_results": "Prüfungsergebnisse", + "practice_results": "Üben", + "not-allowed": "Nicht erlaubt", + "attempt-limit": "Versuchslimit erreicht", + "attempt-not-possible": "Versuch abgebrochen" + } }, "Home": { "description": "Create your own Course to boost your knowledge to the next level. (de)" diff --git a/src/i18n/locales/de.ts b/src/i18n/locales/de.ts index 208e23eb..c49c8f5b 100644 --- a/src/i18n/locales/de.ts +++ b/src/i18n/locales/de.ts @@ -39,7 +39,23 @@ export default { 'minute_label#other': 'minuten', minute_label: 'minuten' }, - jump_back_button_label: 'Bearbeiten' + jump_back_button_label: 'Bearbeiten', + Breadcrumbs: { + root: 'Home', + courses: 'Kurse', + discover: 'Entdecken', + practice: 'Üben', + edit: 'Bearbeiten', + create: 'Erstellen', + account: 'Account', + start: 'Start', + results: 'Ergebnisse', + examination_results: 'Prüfungsergebnisse', + practice_results: 'Üben', + 'not-allowed': 'Nicht erlaubt', + 'attempt-limit': 'Versuchslimit erreicht', + 'attempt-not-possible': 'Versuch abgebrochen' + } }, Home: { description: 'Create your own Course to boost your knowledge to the next level. (de)' diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 133e29d8..fbcf3921 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -38,7 +38,24 @@ "minute_label#other": "minutes", "minute_label": "minutes" }, - "jump_back_button_label": "Jump back" + "jump_back_button_label": "Jump back", + "Breadcrumbs": { + "root": "Home", + "courses": "Courses", + "discover": "Discover", + "practice": "Practice", + "edit": "Edit", + "create": "Create", + "account": "Account", + "start": "Start", + "results": "Results", + "examination_results": "Examination Results", + "practice_results": "Practice", + + "not-allowed": "Not Allowed", + "attempt-limit": "Attempt Limit Reached", + "attempt-not-possible": "Attempt aborted" + } }, "Home": { "description": "Create your own Courses to boost your knowledge to the next level. (en)" diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index d82c17eb..2740c023 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -39,7 +39,23 @@ export default { 'minute_label#other': 'minutes', minute_label: 'minutes' }, - jump_back_button_label: 'Jump back' + jump_back_button_label: 'Jump back', + Breadcrumbs: { + root: 'Home', + courses: 'Courses', + discover: 'Discover', + practice: 'Practice', + edit: 'Edit', + create: 'Create', + account: 'Account', + start: 'Start', + results: 'Results', + examination_results: 'Examination Results', + practice_results: 'Practice', + 'not-allowed': 'Not Allowed', + 'attempt-limit': 'Attempt Limit Reached', + 'attempt-not-possible': 'Attempt aborted' + } }, Home: { description: 'Create your own Courses to boost your knowledge to the next level. (en)' From 58e3274442fc6cd1d176aaab65c1c69df498b9da Mon Sep 17 00:00:00 2001 From: Marty Byrde <45905689+Marty-Byrde@users.noreply.github.com> Date: Sat, 28 Mar 2026 07:55:09 +0100 Subject: [PATCH 7/8] ref: resolved moved component import path issue --- src/app/[locale]/results/[courseId]/practice/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/[locale]/results/[courseId]/practice/page.tsx b/src/app/[locale]/results/[courseId]/practice/page.tsx index 2560ca55..2b554e00 100644 --- a/src/app/[locale]/results/[courseId]/practice/page.tsx +++ b/src/app/[locale]/results/[courseId]/practice/page.tsx @@ -3,7 +3,7 @@ import { getCourseById } from '@/database/course/select' import { QuestionCorrectnessPieChart } from '@/src/components/charts/QuestionCorrectnessPieChart' import { ExamQuestionDurationChart } from '@/src/components/charts/QuestionDurationChart' import { QuestionScorePlotCard } from '@/src/components/charts/QuestionScorePlot' -import ExamQuestionResultTable from '@/src/components/courses/[share_token]/results/ExamQuestionResultTable' +import ExamQuestionResultTable from '@/src/components/results/examination/ExamQuestionResultTable' import { PracticeResultsBreadcrumbs } from '@/src/components/results/practice/PracticeResultsBreadcrumbs' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/src/components/shadcn/card' import PageHeading from '@/src/components/Shared/PageHeading' From 9514611b0752a2a1f6655cfab529528295a5b9b4 Mon Sep 17 00:00:00 2001 From: Marty Byrde <45905689+Marty-Byrde@users.noreply.github.com> Date: Sat, 28 Mar 2026 08:04:34 +0100 Subject: [PATCH 8/8] ref: added tooltip to show exam results action-item --- src/components/courses/(hamburger-menu)/CourseActionMenu.tsx | 2 +- src/i18n/locales/de.json | 3 ++- src/i18n/locales/de.ts | 3 ++- src/i18n/locales/en.json | 3 ++- src/i18n/locales/en.ts | 3 ++- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/components/courses/(hamburger-menu)/CourseActionMenu.tsx b/src/components/courses/(hamburger-menu)/CourseActionMenu.tsx index c22682f9..467ae696 100644 --- a/src/components/courses/(hamburger-menu)/CourseActionMenu.tsx +++ b/src/components/courses/(hamburger-menu)/CourseActionMenu.tsx @@ -143,7 +143,7 @@ export default function CourseActionMenu({ id, questions, share_key, owner_id, c - + {t('show_exam_results.label')} diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 8bbd235c..bec865c4 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -438,7 +438,8 @@ "label": "Kurs duplizieren" }, "show_exam_results": { - "label": "Prüfungs Ergebnisse" + "label": "Prüfungs Ergebnisse", + "tooltip": "Dir fehlen Berechtigungen um Prüfungsergebnisse einzusehen!" }, "inspect_statistics": { "label": "Statistik anzeigen" diff --git a/src/i18n/locales/de.ts b/src/i18n/locales/de.ts index c49c8f5b..85ea860e 100644 --- a/src/i18n/locales/de.ts +++ b/src/i18n/locales/de.ts @@ -442,7 +442,8 @@ export default { label: 'Kurs duplizieren' }, show_exam_results: { - label: 'Prüfungs Ergebnisse' + label: 'Prüfungs Ergebnisse', + tooltip: 'Dir fehlen Berechtigungen um Prüfungsergebnisse einzusehen!' }, inspect_statistics: { label: 'Statistik anzeigen' diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index fbcf3921..ac3800e9 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -448,7 +448,8 @@ "label": "Clone Course" }, "show_exam_results": { - "label": "Show Examination Results" + "label": "Show Examination Results", + "tooltip": "You are not allowed to view exam results!" }, "inspect_statistics": { "label": "Inspect Statistics" diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index 2740c023..d0bb0788 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -448,7 +448,8 @@ export default { label: 'Clone Course' }, show_exam_results: { - label: 'Show Examination Results' + label: 'Show Examination Results', + tooltip: 'You are not allowed to view exam results!' }, inspect_statistics: { label: 'Inspect Statistics'