Skip to content

Ref: Introduce minor UX related improvements i.e. localization, navigation locations#293

Open
Marty-Byrde wants to merge 27 commits into
canaryfrom
ref/minor-improvements
Open

Ref: Introduce minor UX related improvements i.e. localization, navigation locations#293
Marty-Byrde wants to merge 27 commits into
canaryfrom
ref/minor-improvements

Conversation

@Marty-Byrde

@Marty-Byrde Marty-Byrde commented Mar 27, 2026

Copy link
Copy Markdown
Member

Note

This pull request mainly improves the authoring and practice experience through small but meaningful UX and localization refinements, fixes a navigation regression in the jump-back flow, and adds a few maintenance updates to keep translations, schema handling, and development workflows more reliable.

Summary

  • Fixes

    • Fixed the jumpBackButton routing so users are sent to the correct stage again after the new content stage shifted stage indexes.
  • Chores

    • Added translation synchronization to the pre-commit workflow so generated locale files and manually maintained JSON files stay aligned.

    • Improved stripDefaultValues handling so array effects are preserved and re-applied correctly, avoiding future schema-related issues.

    • Added a dedicated development build script that exposes all build errors instead of only the first one.

  • Refactors

    • Improved course editing breadcrumbs by introducing a dedicated edit/[id] layout so course names are shown instead of raw IDs.

    • Tightened drag-drop question validation by preventing authors from removing all answer options.

    • Improved form error feedback by enabling icons in more FormFieldError usages.

    • Expanded the Field component with textarea support and applied it to description fields for a better editing experience.

    • Improved tooltip accessibility by allowing toggling, especially benefiting mobile users.

    • Localized several UI areas, including generic breadcrumbs, practice breadcrumbs, practice results breadcrumbs, content page breadcrumbs, and stopwatch duration formatting.

    • Refined breadcrumb behavior so custom practice breadcrumbs align better with the rest of the app by starting from the root.

    • Cleaned up minor internal behavior, including removing unnecessary schema logging and improving the DOM structure of the RichTextEditor to better respect layout constraints.

    • Added dummy exam results in KnowCMenu for internal/testing-related purposes.

  • Styles

    • Reduced the maximum width of the practice question container on large screens to improve layout balance and readability.

Changelog

Changelog

  • Fixes:

    • Resolved jumpBackButton stage indecies (eccc8a37)
      The reason for this is that with the introduction of the new content stage the index of the remaining stages was increased by one. This meant that the Jumpback button redirected users to the wrong stage when clicked. This issue is now resolved.
  • Chores:

    • Added translation synchronization to pre-commit (d4e3df6b)
      This way the auto-generated locale-files and the .json files that are manually edited are always in sync when changes are committed.

    • Resolved stripping of array effects in stripDefaultValues (66b74687)
      Previously the stripZodDefaultValues utility function stripped all effects from a given array when stripping it from default values. To prevent potential issues because of it in the future, the stripped checks are now re-applied.

    • Added development build script (63da9040)
      This development build script shows all build errors and not just a single one.

  • Refactors:

    • Added dummy exam results to KnowCMenu (19d77f3c)

    • Added edit/[id] layout to render specific Breadcrumbs (54c9de92)
      The reason for this change is that previously the edit-course page showed the generic breadcrumb which showed the actual course id. Since the course-id is not a good breadcrumb the name is used instead, thus a custom Breadcrumbs were defined in the new layout to override the generic breadcrumbs.

    • Added minimum drag-drop answer constraint (d96ff4d2)
      The reason for this change is that previously users able to delete all answer-options when creating a drag-drop question. To prevent this edge-case a min constraint was introduces to the respective schema to disallow this case.

    • Enabled showIcon in FormFieldError usages (4a3d5ed5)
      The reason for this change is that this way the general errors for choice- and drag-drop answer errors also include an error-icon, just like field-errors using the Field component do.

    • Improved tooltip accessibility by allowing toggling (1b4d1626)
      This way users on mobile devices are also able to access tooltips. At the same time this allows users on desktop screens to also toggle tooltips.

    • Added textarea support to Field component (ff90fc8d)
      This way fields for e.g. descriptions can be rendered as a Textarea instead of a single-line input. This can be done by setting the variant to textarea.

    • Applied Field variant textarea for descriptions (601b3dac)
      This way the descriptions fields used in the GeneralSection and the CourseContentDialog are now rendering a textarea instead of a single-line input.

    • Removed log statement in schemaDefaults (58d59f9a)
      Previously the schemaDefaults utility function logged "unknown schema type" when a property was of type any, unknown or undefined. However, since all these types are instantiated as undefined it is not worth logging.

    • Localized PracticeBreadcrumbs texts (4b368856)

    • Localized StopWatch duration format based on locale (ea02cfe2)

    • Extended PracticeBreadcrumbs to start from root (9a3c110e)
      This way these custom breadcrumbs align with the other breadcrumbs shown on other pages, which all start from the root page.

    • Localized GenericBreadcrumb page segments (4b5e4703)
      The GenericBreadcrumb component now displays the translation for a given page-segement-key or if it does not exist it shows the segment (key) as before.

    • Localized PracticeResultsBreadcrumbs texts (3dd06745)

    • Localized ContentPageBreadcrumbs texts (7a39842e)

    • Improved DOM structure of RichTextEditor (cd68b4aa)
      The reason for this change is that previously the editor-pane (EditorContent) in some cases causes its container to grow outside of its max-height constraint. By removing an obsolete outer wrapper and moving the constraints directly to the editor pane these issues are resolved.

  • Styles:

    • Lowered max-w size of practice-q container (b8e45eeb)
      Previously the width of the grid-cell that shows the practice question, practice progress had a max-width of 4/5 on large screens. Now the max-w is slightly smaller on larger screens, namely to 50% of the viewport width.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added pinnable tooltip functionality for better user control.
    • Introduced textarea option for text input fields.
  • Improvements

    • Enhanced breadcrumb navigation with localized labels throughout the app.
    • Improved practice page layout and responsiveness.
    • Better course editing workflow with updated navigation flows.
    • Enhanced form validation for question answers.
  • Accessibility

    • Added screen reader labels for category switchers and interactive elements.
    • Improved locale-aware time formatting.
  • Localization

    • Expanded German and English translations for breadcrumbs and practice navigation.

Previously the width of the grid-cell that shows the practice question, practice progress had a max-width of 4/5 on large screens. Now the max-w is slightly smaller on larger screens, namely to 50% of the viewport width.
This way the auto-generated locale-files and the `.json` files that are manually edited are always in sync when changes are committed.
The reason for this change is that previously the edit-course page showed the generic breadcrumb which showed the actual course id. Since the course-id is not a good breadcrumb the name is used instead, thus a custom Breadcrumbs were defined in the new layout to override the generic breadcrumbs.
The reason for this change is that previously users able to delete all answer-options when creating a drag-drop question. To prevent this edge-case a min constraint was introduces to the respective schema to disallow this case.
The reason for this change is that this way the general errors for choice- and drag-drop answer errors also include an error-icon, just like field-errors using the `Field` component do.
This way users on mobile devices are also able to access tooltips. At the same time this allows users on desktop screens to also toggle tooltips.
This way fields for e.g. descriptions can be rendered as a Textarea instead of a single-line input. This can be done by setting the `variant` to `textarea`.
This way the descriptions fields used in the `GeneralSection` and the `CourseContentDialog` are now rendering a textarea instead of a single-line input.
Previously the `stripZodDefaultValues` utility function stripped all effects from a given array when stripping it from default values. To prevent potential issues because of it in the future, the stripped checks are now re-applied.
Previously the `schemaDefaults` utility function logged "unknown schema type" when a property was of type `any`, `unknown` or `undefined`. However, since all these types are instantiated as `undefined` it is not worth logging.
@coderabbitai

coderabbitai Bot commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Adds translation sync to pre-commit and npm scripts, introduces a textarea variant for the shared Field, adds pinnable Tooltip state, converts multiple breadcrumb components to server-side i18n, adds an edit layout that fetches a course, tightens Zod array handling and strip-default logic, and adjusts several UI layout/props.

Changes

Cohort / File(s) Summary
Pre-commit & npm scripts
.husky/pre-commit, package.json
Pre-commit now runs yarn sync-translations, stages generated src/i18n/locales/*.ts, then runs npx lint-staged --allow-empty; added sync-translations and build:dev npm scripts.
Form Field & usages
src/components/Shared/form/Field.tsx, src/components/courses/create/(sections)/*, src/components/courses/create/(create-question)/*
Field gained variant overloads to support textarea; updated typings/overloads and onChange handling; several description fields switched to variant='textarea'; FieldError usages now pass showIcon.
Tooltip & Shared UI
src/components/Shared/Tooltip.tsx, src/components/Shared/Breadcrumb/GenericBreadcrumb.tsx, src/components/Shared/StopwatchTime.tsx
Tooltip gained pinnable prop, local hover/pin state and controlled open handling; GenericBreadcrumb and StopwatchTime now use scoped/server i18n and locale-aware duration formatting.
Course pages & breadcrumbs
src/app/[locale]/courses/edit/[id]/layout.tsx, src/app/[locale]/courses/[share_token]/practice/page.tsx, src/components/courses/[share_token]/practice/PracticeBreadcrumbs.tsx, src/components/results/practice/PracticeResultsBreadcrumbs.tsx
Added async EditLayout that fetches course and calls notFound() when missing; practice/result/content breadcrumbs converted to async server components using i18n; practice page now passes courseId/courseName and adjusts a 2xl width class.
Course action & small UI tweaks
src/components/courses/(hamburger-menu)/CourseActionMenu.tsx, src/components/courses/create/(sections)/GeneralSection.tsx, src/components/courses/create/(sections)/QuestionsSection.tsx, src/components/courses/create/(sections)/SettingsSection.tsx
Removed disabled statistics menu item (entry removed); description fields switched to textarea where noted; adjusted CardStageJumpButton targetStage values in QuestionsSection and SettingsSection.
Schemas & utils
src/schemas/QuestionSchema.ts, src/schemas/utils/schemaDefaults.ts, src/schemas/utils/stripZodDefaultValues.ts
Added .min(1) to drag-drop answers array; removed a stray console.log; improved stripZodDefault for arrays to reconstruct element schema and reapply array checks (min, max, length, nonempty, and refine).
Rich text editor & content
src/components/tiptap-examples/RichTextEditor.tsx, src/components/courses/contents/[courseId]/ContentRenderer.tsx
RichTextEditor added optional `growth?: 'content'
i18n locale files
src/i18n/locales/en.{json,ts}, src/i18n/locales/de.{json,ts}, src/i18n/locales/*.ts
Added new Shared.Breadcrumbs keys (practice/category labels, SR-only label, practice_page, contents) for EN/DE; generated TS locale files updated and staged by pre-commit workflow.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested labels

Code Improvements, Visual Improvements, bug-fix, released on @canary``, released

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: introducing localization of breadcrumbs and improving navigation locations throughout the codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ref/minor-improvements

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

This development build script shows all build errors and not just a single one.
@codecov

codecov Bot commented Mar 27, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (5)
src/app/[locale]/courses/edit/[id]/layout.tsx (1)

14-32: Inconsistent BreadcrumbItem wrapping pattern.

The "Home" link (line 16-18) and BreadcrumbPage (line 30) are not wrapped in BreadcrumbItem, while "Courses" and "Edit" are. For consistent styling and semantic structure, all breadcrumb entries should be wrapped in BreadcrumbItem.

♻️ Proposed fix for consistent structure
       <Breadcrumb>
         <BreadcrumbList>
-          <BreadcrumbLink asChild>
-            <Link href={`/`}>Home</Link>
-          </BreadcrumbLink>
+          <BreadcrumbItem>
+            <BreadcrumbLink asChild>
+              <Link href='/'>Home</Link>
+            </BreadcrumbLink>
+          </BreadcrumbItem>
           <BreadcrumbSeparator />

           <BreadcrumbItem>
             <BreadcrumbLink asChild>
-              <Link href={`/courses`}>Courses</Link>
+              <Link href='/courses'>Courses</Link>
             </BreadcrumbLink>
           </BreadcrumbItem>
           <BreadcrumbSeparator />
           <BreadcrumbItem>Edit</BreadcrumbItem>

           <BreadcrumbSeparator />
-          <BreadcrumbPage>{course.name}</BreadcrumbPage>
+          <BreadcrumbItem>
+            <BreadcrumbPage>{course.name}</BreadcrumbPage>
+          </BreadcrumbItem>
         </BreadcrumbList>
       </Breadcrumb>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/`[locale]/courses/edit/[id]/layout.tsx around lines 14 - 32, The
breadcrumb markup is inconsistent: wrap the "Home" link and the final page title
so every entry uses BreadcrumbItem like the others. Update the JSX around
Breadcrumb/BreadcrumbList to place <BreadcrumbItem> around the Home
<BreadcrumbLink asChild><Link href={`/`}>Home</Link></BreadcrumbLink> and around
<BreadcrumbPage>{course.name}</BreadcrumbPage>, keeping BreadcrumbSeparator
placements the same and preserving existing BreadcrumbLink/BreadcrumbPage
components.
src/schemas/QuestionSchema.ts (1)

114-114: Translation key reuse from SingleChoice namespace in DragDrop schema.

The validation correctly enforces a minimum of one answer, but uses schemas.Question.SingleChoice.answers.min_answer_count for a drag-drop question. For consistency with getMultipleChoiceAnswerSchema (line 68), which has its own key (schemas.Question.MultipleChoice.answers.min_constraint), consider either:

  1. Adding a dedicated DragDrop translation key, or
  2. Using a shared key under schemas.Question.Shared.answers.min_answer_count

The current approach works but may confuse translators or future maintainers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/schemas/QuestionSchema.ts` at line 114, The DragDrop answer schema is
reusing the SingleChoice translation key; update the validation in
getDragDropAnswerSchema to reference a DragDrop-specific or shared key instead
(e.g., 'schemas.Question.DragDrop.answers.min_answer_count' or
'schemas.Question.Shared.answers.min_answer_count') and add the matching
translation entry(s) to the locale files so translators see the correct scope;
ensure the t(...) call in the .min(...) validator is updated to the chosen key.
src/components/courses/create/(create-question)/CreateQuestionDialog.tsx (1)

467-467: Consider fixing the type parameter while modifying this line.

This line uses <FieldError<ChoiceQuestion> inside DragDropQuestionAnswers, but should use DragDropQuestion for type consistency:

♻️ Suggested fix
-      <FieldError<ChoiceQuestion> field='answers' errors={errors} showIcon />
+      <FieldError<DragDropQuestion> field='answers' errors={errors} showIcon />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/courses/create/`(create-question)/CreateQuestionDialog.tsx at
line 467, The FieldError generic is using the wrong type: change the type
parameter from ChoiceQuestion to DragDropQuestion for the FieldError used inside
DragDropQuestionAnswers in CreateQuestionDialog.tsx; locate the FieldError
component instance (FieldError<ChoiceQuestion> field='answers' errors={errors}
showIcon) and replace the generic so it becomes FieldError<DragDropQuestion>,
ensuring the type aligns with the DragDropQuestionAnswers component and related
form data types.
src/components/Shared/form/Field.tsx (1)

100-116: Multiple Any casts reduce type safety in event handlers.

The casts on lines 102, 108, and 112 are pragmatic workarounds for the discriminated union, but they suppress type checking. Consider narrowing the event handler types based on variant:

♻️ Optional: Type-narrowed event handlers
                  onFocus={(e) => {
                    setIsFocused(true)
-                   props.onFocus?.(e as Any)
+                   ;(props as { onFocus?: (e: typeof e) => void }).onFocus?.(e)
                  }}
                  onBlur={(e) => {
                    setIsFocused(false)
-                   props.onBlur?.(e as Any)
+                   ;(props as { onBlur?: (e: typeof e) => void }).onBlur?.(e)
                    field.onBlur()
                  }}

This preserves type inference while avoiding the broad Any escape hatch.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Shared/form/Field.tsx` around lines 100 - 116, The event
handlers in the ControlledComponent use broad Any casts (props.onFocus?.(e as
Any), props.onBlur?.(e as Any), and ControlledComponent props spread) which
suppress type checking; update the handlers to narrow the event types instead:
derive the correct React event type from ControlledComponent (e.g.,
React.FocusEvent<HTMLInputElement> or the component's input type) and type the
local onFocus/onBlur callback parameters accordingly, replace the Any casts with
properly typed parameters when calling props.onFocus and props.onBlur, and
ensure fieldOnChange uses the matching ChangeEvent type so you can remove the
Any casts and preserve type safety around ControlledComponent, setIsFocused,
field.onBlur, and fieldOnChange.
src/components/Shared/Tooltip.tsx (1)

19-24: Effect may skip necessary updates due to stale isPinned reference.

The effect reads isPinned but excludes it from dependencies (with eslint-disable). When config.open changes but the closure still holds a stale isPinned value, the config.open === isPinned check may incorrectly return true, skipping the update.

Consider storing the previous config.open value instead:

♻️ Suggested fix using previous value tracking
-  useEffect(() => {
-    if (config.open === undefined || config.open === isPinned) return
-
-    // eslint-disable-next-line react-hooks/set-state-in-effect
-    setPinned(config.open)
-  }, [config.open])
+  const prevConfigOpen = useRef(config.open)
+  useEffect(() => {
+    if (config.open !== undefined && config.open !== prevConfigOpen.current) {
+      setPinned(config.open)
+    }
+    prevConfigOpen.current = config.open
+  }, [config.open])

This requires importing useRef as well.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Shared/Tooltip.tsx` around lines 19 - 24, The effect currently
reads isPinned but omits it from the dependency array, causing stale-closure
bugs; change the effect to track the previous config.open using a useRef (import
useRef) — e.g., create prevOpenRef, compare prevOpenRef.current to config.open
and only run setPinned(config.open) when they differ (and update
prevOpenRef.current = config.open afterwards); update the effect dependencies to
include config.open (and remove the eslint-disable) and keep using setPinned and
isPinned as the state references inside Tooltip.tsx.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.husky/pre-commit:
- Around line 4-5: The pre-commit hook currently runs "yarn sync-translations"
then stages only "git add src/i18n/locales/*.ts", but the
prepare-i18n_ally-locales.ts script also writes JSON files; update the hook so
it stages JSON as well (e.g., change the git add to include both ts and json
like "git add src/i18n/locales/*.{ts,json}" or add an additional "git add
src/i18n/locales/*.json" line) to ensure generated locale JSON files are not
omitted from commits.

In `@src/components/courses/`(hamburger-menu)/CourseActionMenu.tsx:
- Around line 149-153: The Link in CourseActionMenu uses the wrong route and
doesn't guard against a null share_key; change the navigation to use the
gatherShareToken pattern (the same helper used elsewhere in this component) to
build the path /courses/{share_token}/results and disable the DropdownMenuItem
when gatherShareToken returns null/undefined. Update the item that currently
links to `/checks/${share_key}/results` to call gatherShareToken (or the local
equivalent), render the Link only when a token exists, and apply the same
disabled styling/prop used by other menu items so the menu entry is
non-interactive when the token is missing.

In `@src/components/Shared/Tooltip.tsx`:
- Around line 36-38: The TooltipTrigger currently passes onClick with asChild
which toggles setPinned even when interactive children handle their own clicks;
update TooltipTrigger usage in Tooltip.tsx so the onClick is either removed or
only attached for non-interactive children: detect interactive children (e.g.,
elements with role/button, onClick/onPress/onPointerDown props, or known
components like Toggle) and avoid merging the onClick into those, or wrap
children in a non-interactive wrapper element and attach the toggle handler
there; reference TooltipTrigger, setPinned and children to locate the code and
implement conditional attachment or a dedicated non-interactive wrapper to
prevent conflicting handlers.

---

Nitpick comments:
In `@src/app/`[locale]/courses/edit/[id]/layout.tsx:
- Around line 14-32: The breadcrumb markup is inconsistent: wrap the "Home" link
and the final page title so every entry uses BreadcrumbItem like the others.
Update the JSX around Breadcrumb/BreadcrumbList to place <BreadcrumbItem> around
the Home <BreadcrumbLink asChild><Link href={`/`}>Home</Link></BreadcrumbLink>
and around <BreadcrumbPage>{course.name}</BreadcrumbPage>, keeping
BreadcrumbSeparator placements the same and preserving existing
BreadcrumbLink/BreadcrumbPage components.

In `@src/components/courses/create/`(create-question)/CreateQuestionDialog.tsx:
- Line 467: The FieldError generic is using the wrong type: change the type
parameter from ChoiceQuestion to DragDropQuestion for the FieldError used inside
DragDropQuestionAnswers in CreateQuestionDialog.tsx; locate the FieldError
component instance (FieldError<ChoiceQuestion> field='answers' errors={errors}
showIcon) and replace the generic so it becomes FieldError<DragDropQuestion>,
ensuring the type aligns with the DragDropQuestionAnswers component and related
form data types.

In `@src/components/Shared/form/Field.tsx`:
- Around line 100-116: The event handlers in the ControlledComponent use broad
Any casts (props.onFocus?.(e as Any), props.onBlur?.(e as Any), and
ControlledComponent props spread) which suppress type checking; update the
handlers to narrow the event types instead: derive the correct React event type
from ControlledComponent (e.g., React.FocusEvent<HTMLInputElement> or the
component's input type) and type the local onFocus/onBlur callback parameters
accordingly, replace the Any casts with properly typed parameters when calling
props.onFocus and props.onBlur, and ensure fieldOnChange uses the matching
ChangeEvent type so you can remove the Any casts and preserve type safety around
ControlledComponent, setIsFocused, field.onBlur, and fieldOnChange.

In `@src/components/Shared/Tooltip.tsx`:
- Around line 19-24: The effect currently reads isPinned but omits it from the
dependency array, causing stale-closure bugs; change the effect to track the
previous config.open using a useRef (import useRef) — e.g., create prevOpenRef,
compare prevOpenRef.current to config.open and only run setPinned(config.open)
when they differ (and update prevOpenRef.current = config.open afterwards);
update the effect dependencies to include config.open (and remove the
eslint-disable) and keep using setPinned and isPinned as the state references
inside Tooltip.tsx.

In `@src/schemas/QuestionSchema.ts`:
- Line 114: The DragDrop answer schema is reusing the SingleChoice translation
key; update the validation in getDragDropAnswerSchema to reference a
DragDrop-specific or shared key instead (e.g.,
'schemas.Question.DragDrop.answers.min_answer_count' or
'schemas.Question.Shared.answers.min_answer_count') and add the matching
translation entry(s) to the locale files so translators see the correct scope;
ensure the t(...) call in the .min(...) validator is updated to the chosen key.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9818ae40-ce4f-48c1-86c5-cea522d09f7a

📥 Commits

Reviewing files that changed from the base of the PR and between a9501ef and 58d59f9.

📒 Files selected for processing (13)
  • .husky/pre-commit
  • package.json
  • src/app/[locale]/courses/[share_token]/practice/page.tsx
  • src/app/[locale]/courses/edit/[id]/layout.tsx
  • src/components/Shared/Tooltip.tsx
  • src/components/Shared/form/Field.tsx
  • src/components/courses/(hamburger-menu)/CourseActionMenu.tsx
  • src/components/courses/create/(create-question)/CreateQuestionDialog.tsx
  • src/components/courses/create/(sections)/CourseContentDialog.tsx
  • src/components/courses/create/(sections)/GeneralSection.tsx
  • src/schemas/QuestionSchema.ts
  • src/schemas/utils/schemaDefaults.ts
  • src/schemas/utils/stripZodDefaultValues.ts
💤 Files with no reviewable changes (1)
  • src/schemas/utils/schemaDefaults.ts

Comment thread .husky/pre-commit
Comment thread src/components/courses/(hamburger-menu)/CourseActionMenu.tsx Outdated
Comment thread src/components/Shared/Tooltip.tsx Outdated
This way these custom breadcrumbs align with the other breadcrumbs shown on other pages, which all start from the root page.
The `GenericBreadcrumb` component now displays the translation for a given page-segement-key or if it does not exist it shows the segment (key) as before.
The reason for this is that with the introduction of the new `content` stage the index of the remaining stages was increased by one. This meant that the `Jumpback` button redirected users to the wrong stage when clicked. This issue is now resolved.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/Shared/StopwatchTime.tsx (1)

15-27: ⚠️ Potential issue | 🟡 Minor

Default delimiter remains English for German output

When no delimiter prop is passed, Line 14 still defaults to ' and ', so German duration units can render with an English conjunction (mixed-language UI).

💡 Suggested fix
-export function StopwatchTime({ start: rawStartDate, delimiter = ' and ' }: { start: Date; delimiter?: string }) {
+export function StopwatchTime({ start: rawStartDate, delimiter }: { start: Date; delimiter?: string }) {
   const currentLocale = useCurrentLocale()
+  const effectiveDelimiter = delimiter ?? (currentLocale === 'de' ? ' und ' : ' and ')
@@
-        { zero: true, delimiter, locale: currentLocale === 'de' ? de : enUS },
+        { zero: true, delimiter: effectiveDelimiter, locale: currentLocale === 'de' ? de : enUS },
       ),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Shared/StopwatchTime.tsx` around lines 15 - 27, The code uses
a fixed/default English delimiter so German output can include an English
conjunction; update the StopwatchTime component to compute a locale-aware
delimiter (e.g., compute a localDelimiter from the existing delimiter prop or
fallback to ' und ' when currentLocale === 'de' and ' and ' otherwise) and pass
that computed localDelimiter into the formatDuration call in computeDifference
(references: currentLocale, delimiter, computeDifference, formatDuration).
Ensure you use the computed localDelimiter everywhere formatDuration is called
so German durations render with the correct conjunction.
🧹 Nitpick comments (4)
src/components/courses/[share_token]/practice/PracticeBreadcrumbs.tsx (2)

53-53: Avoid runtime string manipulation on translated values.

Applying .toLowerCase().replace(/ /g, '-') to a translated string is fragile across locales—different languages may have varying spacing, casing rules, or special characters. Consider either:

  1. Adding a separate i18n key for the slug/display format
  2. Using the raw category value for display when it's _none_/undefined
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/courses/`[share_token]/practice/PracticeBreadcrumbs.tsx at
line 53, The breadcrumb currently transforms the translated label with
.toLowerCase().replace(/ /g, '-') which is fragile; update the BreadcrumbPage
rendering logic (where BreadcrumbPage is used and the variable category is
checked) to stop mutating the i18n string—either introduce and use a new i18n
key for the slug/display form (e.g., a separate practice_category_all_slug key)
or display the raw category value when category === '_none_' || category ===
undefined and leave the translation untouched (use
t('practice_category_all_label') only for display without toLowerCase/replace).

40-41: Consider making "practice" a navigable link for consistency.

The "practice" breadcrumb item is plain text while other items are links. If there's a practice landing/overview page, consider wrapping this in a BreadcrumbLink for consistent navigation UX.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/courses/`[share_token]/practice/PracticeBreadcrumbs.tsx around
lines 40 - 41, The "practice" breadcrumb is currently rendered as plain text
(BreadcrumbItem with t('practice')); change it to a navigable item by wrapping
it in a BreadcrumbLink (e.g., <BreadcrumbItem><BreadcrumbLink
href={...}>{t('practice')}</BreadcrumbLink></BreadcrumbItem>) so it matches
other breadcrumb items in PracticeBreadcrumbs.tsx and points to the practice
landing/overview route for the current share_token context; ensure the
href/route generation uses the same token/params logic as the other breadcrumb
links in this component.
src/components/Shared/Breadcrumb/GenericBreadcrumb.tsx (1)

44-52: Dynamic segment translation may fall back to raw keys for unknown paths.

Using t(segment as Any) assumes every URL segment has a corresponding i18n key in Shared.Breadcrumbs. If a segment (e.g., a dynamic ID like a UUID) lacks a translation key, the behavior depends on the i18n library configuration—it may display the raw key string or an empty value.

Consider adding a fallback mechanism to handle untranslated segments gracefully:

💡 Suggested fallback pattern
-                <BreadcrumbPage>{t(segment as Any)}</BreadcrumbPage>
+                <BreadcrumbPage>{t(segment as Any) || segment}</BreadcrumbPage>
               ) : (
                 <BreadcrumbLink asChild>
-                  <Link href={'/' + pages.slice(0, i + 1).join('/')}>{t(segment as Any)}</Link>
+                  <Link href={'/' + pages.slice(0, i + 1).join('/')}>{t(segment as Any) || segment}</Link>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Shared/Breadcrumb/GenericBreadcrumb.tsx` around lines 44 - 52,
The breadcrumb currently calls t(segment as Any) for every URL segment (in
GenericBreadcrumb.tsx inside the pages?.map loop, around
BreadcrumbPage/BreadcrumbLink and isCurrentPage), which can render raw keys for
dynamic segments; change the rendering to first check whether a translation
exists (or if the segment looks dynamic like a UUID/ID) and if not use a safe
fallback such as a humanized/capitalized version of the segment (or pass a
defaultValue to the i18n call). Update the map rendering to use that
existence-check + fallback approach for both BreadcrumbPage and BreadcrumbLink
so untranslated segments show a readable label instead of the raw key.
src/components/courses/create/(sections)/SettingsSection.tsx (1)

41-41: Replace hard-coded stage indices with shared stage constants.

Line 41 introduces another literal stage index (4). Because CardStageJumpButton passes this directly (src/components/Shared/CardStageJumpButton.tsx:13-27) and setStage is unbounded (src/hooks/Shared/MultiStage/MultiStageStore.ts:30-44), future stage reordering can silently break navigation.

Proposed refactor
+const COURSE_CREATE_STAGE = {
+  QUESTIONS: 3,
+  SETTINGS: 4,
+} as const
+
 export default function SettingsSection({
   jumpBackButtons,
   className,
   ...config
 }: { jumpBackButtons?: boolean; className?: string } & Omit<UseFormProps<CourseSettings>, 'resolver' | 'defaultValues'>) {
@@
-          {jumpBackButtons && <CardStageJumpButton targetStage={4} />}
+          {jumpBackButtons && <CardStageJumpButton targetStage={COURSE_CREATE_STAGE.SETTINGS} />}
@@
-          {jumpBackButtons && <CardStageJumpButton targetStage={3} />}
+          {jumpBackButtons && <CardStageJumpButton targetStage={COURSE_CREATE_STAGE.QUESTIONS} />}
@@
-          {jumpBackButtons && <CardStageJumpButton targetStage={3} />}
+          {jumpBackButtons && <CardStageJumpButton targetStage={COURSE_CREATE_STAGE.QUESTIONS} />}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/courses/create/`(sections)/SettingsSection.tsx at line 41,
SettingsSection currently uses a hard-coded stage index (4) when rendering
<CardStageJumpButton targetStage={4} />, which can break navigation if stages
are reordered; replace the literal with a shared stage constant (e.g., import
and use a named constant like COURSE_SETTINGS_STAGE or STAGES.Settings) so the
jump target is driven by the same enum used by MultiStageStore and setStage,
update the import in SettingsSection to reference that shared stage constant,
and ensure any other usages of the numeric literal (including in
CardStageJumpButton calls) are migrated to the same shared constant to keep
navigation stable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/courses/`[share_token]/practice/PracticeBreadcrumbs.tsx:
- Around line 33-37: Breadcrumb item currently links to the edit page which may
be inaccessible to practice participants; update the Link href in the
PracticeBreadcrumbs component (the BreadcrumbLink containing Link with
courseId/courseName) to point to a view-only route such as
`/courses/${courseId}` or the practice landing route like
`/courses/${courseId}/practice` instead of `/courses/${courseId}/edit`, and if
your app requires, add a conditional to render the edit link only when the
current user has edit permission.

In `@src/components/results/practice/PracticeResultsBreadcrumbs.tsx`:
- Around line 29-31: The breadcrumb components are nested incorrectly in
PracticeResultsBreadcrumbs: currently BreadcrumbPage wraps BreadcrumbItem;
update the JSX so BreadcrumbItem is the outer wrapper and BreadcrumbPage is
inside it (i.e., wrap BreadcrumbPage with BreadcrumbItem and keep the translated
label t('results') inside BreadcrumbPage) to match the pattern used by
PracticeBreadcrumbs and shadcn/ui.

---

Outside diff comments:
In `@src/components/Shared/StopwatchTime.tsx`:
- Around line 15-27: The code uses a fixed/default English delimiter so German
output can include an English conjunction; update the StopwatchTime component to
compute a locale-aware delimiter (e.g., compute a localDelimiter from the
existing delimiter prop or fallback to ' und ' when currentLocale === 'de' and '
and ' otherwise) and pass that computed localDelimiter into the formatDuration
call in computeDifference (references: currentLocale, delimiter,
computeDifference, formatDuration). Ensure you use the computed localDelimiter
everywhere formatDuration is called so German durations render with the correct
conjunction.

---

Nitpick comments:
In `@src/components/courses/`[share_token]/practice/PracticeBreadcrumbs.tsx:
- Line 53: The breadcrumb currently transforms the translated label with
.toLowerCase().replace(/ /g, '-') which is fragile; update the BreadcrumbPage
rendering logic (where BreadcrumbPage is used and the variable category is
checked) to stop mutating the i18n string—either introduce and use a new i18n
key for the slug/display form (e.g., a separate practice_category_all_slug key)
or display the raw category value when category === '_none_' || category ===
undefined and leave the translation untouched (use
t('practice_category_all_label') only for display without toLowerCase/replace).
- Around line 40-41: The "practice" breadcrumb is currently rendered as plain
text (BreadcrumbItem with t('practice')); change it to a navigable item by
wrapping it in a BreadcrumbLink (e.g., <BreadcrumbItem><BreadcrumbLink
href={...}>{t('practice')}</BreadcrumbLink></BreadcrumbItem>) so it matches
other breadcrumb items in PracticeBreadcrumbs.tsx and points to the practice
landing/overview route for the current share_token context; ensure the
href/route generation uses the same token/params logic as the other breadcrumb
links in this component.

In `@src/components/courses/create/`(sections)/SettingsSection.tsx:
- Line 41: SettingsSection currently uses a hard-coded stage index (4) when
rendering <CardStageJumpButton targetStage={4} />, which can break navigation if
stages are reordered; replace the literal with a shared stage constant (e.g.,
import and use a named constant like COURSE_SETTINGS_STAGE or STAGES.Settings)
so the jump target is driven by the same enum used by MultiStageStore and
setStage, update the import in SettingsSection to reference that shared stage
constant, and ensure any other usages of the numeric literal (including in
CardStageJumpButton calls) are migrated to the same shared constant to keep
navigation stable.

In `@src/components/Shared/Breadcrumb/GenericBreadcrumb.tsx`:
- Around line 44-52: The breadcrumb currently calls t(segment as Any) for every
URL segment (in GenericBreadcrumb.tsx inside the pages?.map loop, around
BreadcrumbPage/BreadcrumbLink and isCurrentPage), which can render raw keys for
dynamic segments; change the rendering to first check whether a translation
exists (or if the segment looks dynamic like a UUID/ID) and if not use a safe
fallback such as a humanized/capitalized version of the segment (or pass a
defaultValue to the i18n call). Update the map rendering to use that
existence-check + fallback approach for both BreadcrumbPage and BreadcrumbLink
so untranslated segments show a readable label instead of the raw key.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9f2dff58-8146-4235-8b49-b1a7d060e424

📥 Commits

Reviewing files that changed from the base of the PR and between 58d59f9 and eccc8a3.

📒 Files selected for processing (13)
  • package.json
  • src/app/[locale]/courses/[share_token]/practice/page.tsx
  • src/components/Shared/Breadcrumb/GenericBreadcrumb.tsx
  • src/components/Shared/StopwatchTime.tsx
  • src/components/courses/(hamburger-menu)/CourseActionMenu.tsx
  • src/components/courses/[share_token]/practice/PracticeBreadcrumbs.tsx
  • src/components/courses/create/(sections)/QuestionsSection.tsx
  • src/components/courses/create/(sections)/SettingsSection.tsx
  • src/components/results/practice/PracticeResultsBreadcrumbs.tsx
  • src/i18n/locales/de.json
  • src/i18n/locales/de.ts
  • src/i18n/locales/en.json
  • src/i18n/locales/en.ts
✅ Files skipped from review due to trivial changes (5)
  • src/components/courses/(hamburger-menu)/CourseActionMenu.tsx
  • src/i18n/locales/en.ts
  • src/i18n/locales/de.json
  • src/i18n/locales/en.json
  • src/i18n/locales/de.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • package.json
  • src/app/[locale]/courses/[share_token]/practice/page.tsx

Comment thread src/components/results/practice/PracticeResultsBreadcrumbs.tsx Outdated
The reason for this change is that previously the editor-pane (`EditorContent`) in some cases causes its container to grow outside of its max-height constraint. By removing an obsolete outer wrapper and moving the constraints directly to the editor pane these issues are resolved.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/components/tiptap-examples/RichTextEditor.tsx (1)

134-156: The 'content' growth option has no effect.

The JSDoc documents growth as accepting 'content' | 'fill', but only 'fill' has explicit handling (Line 195). The 'content' option behaves identically to undefined. Consider either:

  • Simplifying to growth?: 'fill' or a boolean like fillContainer?: boolean
  • Or documenting 'content' as the explicit default for clarity

This is a minor API design consideration.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/tiptap-examples/RichTextEditor.tsx` around lines 134 - 156,
The growth prop currently accepts 'content' | 'fill' but only 'fill' is handled,
so simplify the API by replacing growth with a boolean fillContainer prop:
update the JSDoc and the RichTextEditor signature (remove size?: 'sm'|'md'|'lg'
growth?: 'content'|'fill' and add fillContainer?: boolean), change any
defaulting to use fillContainer (previously growth === 'fill'), and update
rendering logic that checks growth to instead check fillContainer; also update
all callers and tests to pass fillContainer where they previously passed
growth:'fill' or leave undefined for content behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/tiptap-examples/RichTextEditor.tsx`:
- Line 214: The new default max-h-[30dvh] on RichTextEditor (in the className
applied where EditorContent is rendered) restricts CourseContentDialog
unexpectedly; update either the default or the dialog usage: in
CourseContentDialog pass growth='fill' and provide an editorPaneClassname that
overrides the height (e.g., matching ContentRenderer's max-h-[58dvh]) when
instantiating RichTextEditor, or remove/relax the hardcoded max-h-[30dvh] in
RichTextEditor so edit forms are not forced to 30dvh; modify the instantiation
in CourseContentDialog (the place that renders <RichTextEditor ... />) or adjust
the className logic in RichTextEditor to honor an editorPaneClassname prop.

---

Nitpick comments:
In `@src/components/tiptap-examples/RichTextEditor.tsx`:
- Around line 134-156: The growth prop currently accepts 'content' | 'fill' but
only 'fill' is handled, so simplify the API by replacing growth with a boolean
fillContainer prop: update the JSDoc and the RichTextEditor signature (remove
size?: 'sm'|'md'|'lg' growth?: 'content'|'fill' and add fillContainer?:
boolean), change any defaulting to use fillContainer (previously growth ===
'fill'), and update rendering logic that checks growth to instead check
fillContainer; also update all callers and tests to pass fillContainer where
they previously passed growth:'fill' or leave undefined for content behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dc6fafd1-6bc4-4bf0-b452-3e6ce1cdf3a0

📥 Commits

Reviewing files that changed from the base of the PR and between eccc8a3 and cd68b4a.

📒 Files selected for processing (8)
  • src/components/courses/(hamburger-menu)/CourseActionMenu.tsx
  • src/components/courses/contents/[courseId]/ContentRenderer.tsx
  • src/components/courses/contents/[courseId]/ContentsPageBreadcrumbs.tsx
  • src/components/tiptap-examples/RichTextEditor.tsx
  • src/i18n/locales/de.json
  • src/i18n/locales/de.ts
  • src/i18n/locales/en.json
  • src/i18n/locales/en.ts
✅ Files skipped from review due to trivial changes (2)
  • src/components/courses/(hamburger-menu)/CourseActionMenu.tsx
  • src/i18n/locales/en.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/i18n/locales/de.json
  • src/i18n/locales/de.ts
  • src/i18n/locales/en.json

Comment thread src/components/tiptap-examples/RichTextEditor.tsx
@Marty-Byrde Marty-Byrde changed the title Ref: Minor improvements Ref: Introduce minor UX related improvements i.e. localization, navigation locations Apr 5, 2026
@Marty-Byrde Marty-Byrde added Done Pull request is ready to be merged and removed Done Pull request is ready to be merged labels Apr 5, 2026
@Marty-Byrde Marty-Byrde moved this from Done to In progress in KnowledgeCheckr Project Apr 5, 2026
Previously (1b4d162), tooltips were updated in a way that users can pin all tooltips when the trigger is clicked. However, this change meant that any element wrapped by the `Tooltip` would pin the respective tooltip when clicked. This was not the intended behavior. Instead the idea was to pin tooltips on click for specific elements like info-icons. Hence, a `pinnable` argument was introduced which when set to true enables this tooltip-pin functionality.
The reason for this change is that because the examination and practice results were unified in the `/[locale]/results` directory the share-key is no longer needed. Hence the old drag-drop that was not removed in the previous migration is now removed.
The reason for this change is that an element wrapped in `BreadcrumbPage` doesn't need to use the `BreadcrumbItem`

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/components/Shared/form/Field.tsx (1)

77-92: Consider narrowing types to reduce as Any casts.

The as Any casts work correctly but bypass type safety. Since TypeScript doesn't narrow discriminated unions after destructuring, this is a known limitation.

💡 Alternative approach using type guards

You could create a helper to narrow the props:

const isTextareaVariant = (v: string, p: unknown): p is TextareaFieldProps => v === 'textarea'

// Then in fieldOnChange:
if (isTextareaVariant(variant, props)) {
  // TypeScript knows props is TextareaFieldProps here
}

However, given the current usage and the number of cast locations, the pragmatic as Any approach is acceptable for this component.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Shared/form/Field.tsx` around lines 77 - 92, The code uses a
blanket cast "as Any" inside fieldOnChange which bypasses TypeScript safety;
replace that with a narrow type guard helper (e.g., isTextareaVariant or
isInputNumber) that inspects variant and props to refine props to
InputFieldProps or TextareaFieldProps before accessing type-specific members,
then use the narrowed type when calling field.onChange (references:
fieldOnChange, variant, props, InputFieldProps, TextareaFieldProps); implement
the guard(s) near this component and use them in the custom onChange branch and
the number-input branch so you can remove the unsafe casts while preserving the
same behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/Shared/Tooltip.tsx`:
- Around line 37-39: The TooltipTrigger currently always includes
aria-label='toggle tooltip' which is incorrect when pinnable is false; update
the TooltipTrigger element so the aria-label is only set when pinnable is true
(e.g., pass aria-label conditionally based on the pinnable prop or omit it
otherwise) and keep the existing onClick behavior using pinnable ? () =>
setPinned(prev => !prev) : undefined; reference TooltipTrigger, pinnable,
setPinned and children to locate the change.

---

Nitpick comments:
In `@src/components/Shared/form/Field.tsx`:
- Around line 77-92: The code uses a blanket cast "as Any" inside fieldOnChange
which bypasses TypeScript safety; replace that with a narrow type guard helper
(e.g., isTextareaVariant or isInputNumber) that inspects variant and props to
refine props to InputFieldProps or TextareaFieldProps before accessing
type-specific members, then use the narrowed type when calling field.onChange
(references: fieldOnChange, variant, props, InputFieldProps,
TextareaFieldProps); implement the guard(s) near this component and use them in
the custom onChange branch and the number-input branch so you can remove the
unsafe casts while preserving the same behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: eddf0699-2840-464d-ab87-8ce859637548

📥 Commits

Reviewing files that changed from the base of the PR and between cd68b4a and 34d600a.

📒 Files selected for processing (4)
  • src/components/Shared/Tooltip.tsx
  • src/components/Shared/form/Field.tsx
  • src/components/courses/(hamburger-menu)/CourseActionMenu.tsx
  • src/components/results/practice/PracticeResultsBreadcrumbs.tsx
💤 Files with no reviewable changes (1)
  • src/components/courses/(hamburger-menu)/CourseActionMenu.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/results/practice/PracticeResultsBreadcrumbs.tsx

Comment thread src/components/Shared/Tooltip.tsx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

1 participant