Skip to content

feat(dashboard): explained terms card, layout fixes, support link#294

Merged
ViktorSvertoka merged 2 commits into
developfrom
feat/ai-explained-terms
Feb 8, 2026
Merged

feat(dashboard): explained terms card, layout fixes, support link#294
ViktorSvertoka merged 2 commits into
developfrom
feat/ai-explained-terms

Conversation

@TiZorii
Copy link
Copy Markdown
Collaborator

@TiZorii TiZorii commented Feb 8, 2026

Summary by CodeRabbit

  • New Features
    • Added "Explained Terms" dashboard module: view, reorder (drag‑and‑drop), hide/restore terms, and persisted order.
  • UI / Layout
    • Expanded dashboard container and adjusted spacing; reduced background padding; support option changed to a Telegram link.
  • Bug Fixes
    • Fixed email truncation in profile card; improved cached‑term highlight visuals and added localized tooltip.
  • Documentation
    • Added translations for explained terms and cached explanations (en, pl, uk).

@netlify
Copy link
Copy Markdown

netlify Bot commented Feb 8, 2026

Deploy Preview for develop-devlovers ready!

Name Link
🔨 Latest commit 6c3a9da
🔍 Latest deploy log https://app.netlify.com/projects/develop-devlovers/deploys/69883f4e3b6c9600087c7e83
😎 Deploy Preview https://deploy-preview-294--develop-devlovers.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Feb 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
devlovers-net Ready Ready Preview, Comment Feb 8, 2026 7:47am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 8, 2026

📝 Walkthrough

Walkthrough

Adds an interactive "Explained Terms" dashboard module, localStorage-backed utilities for hiding and ordering terms, UI/layout tweaks to the dashboard page, i18n string additions, and small component styling/regex updates.

Changes

Cohort / File(s) Summary
Dashboard page & layout
frontend/app/[locale]/dashboard/page.tsx, frontend/components/header/MainSwitcher.tsx
Render new ExplainedTermsCard; expand container width/padding and adjust DynamicGridBackground usage; add isDashboardPath() to layout routing logic.
Explained Terms feature
frontend/components/dashboard/ExplainedTermsCard.tsx, frontend/lib/ai/hiddenTerms.ts, frontend/lib/ai/termOrder.ts
New client component with modal, hide/restore, drag-and-drop reorder; two new localStorage utilities for hidden terms and term order with browser guards and error handling.
Component tweaks
frontend/components/dashboard/ProfileCard.tsx, frontend/components/q&a/HighlightCachedTerms.tsx
Layout fixes (min-w-0, truncate email); add i18n for cached-term tooltip, update regex to Unicode-aware pattern and adjust cached-term styling.
Localization
frontend/messages/en.json, frontend/messages/pl.json, frontend/messages/uk.json
Add dashboard.quizSaved.explainedTerms block and aiHelper.cachedTooltip; minor footer/phrase wording updates across locales.
Package/manifest
package.json
Small manifest changes (lines added/removed noted in diff summary).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Dashboard as ExplainedTermsCard
    participant Storage as localStorage
    participant AI as AIWordHelper
    participant i18n as Translate

    User->>Dashboard: Mount / open dashboard
    Dashboard->>Storage: getHiddenTerms(), getTermOrder()
    Storage-->>Dashboard: hidden set, saved order
    Dashboard->>i18n: load strings
    i18n-->>Dashboard: localized text

    User->>Dashboard: Click term
    Dashboard->>AI: open detail modal with term
    AI-->>User: show explanation

    User->>Dashboard: Drag term
    Dashboard->>Storage: saveTermOrder(updatedOrder)

    User->>Dashboard: Hide term
    Dashboard->>Storage: hideTermFromDashboard(term)

    User->>Dashboard: Restore term
    Dashboard->>Storage: unhideTermFromDashboard(term)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

UI

Suggested reviewers

  • ViktorSvertoka
  • AM1007

Poem

🐰 I hop through terms both hidden and shown,
I nudge them about till their order is known.
A click brings a helper, a swap keeps the score,
localStorage guards them forevermore.
Hooray for the dashboard — a neat little hop! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 reflects the main changes: a new ExplainedTermsCard component for the dashboard, layout/styling fixes across multiple components, and a Telegram support link replacement.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/ai-explained-terms

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In `@frontend/app/`[locale]/dashboard/page.tsx:
- Around line 113-115: ExplainedTermsCard currently never shows the localized
empty state; update the component (ExplainedTermsCard) to check terms.length (or
hasTerms) and when zero render the two translation keys
dashboard.explainedTerms.empty and dashboard.explainedTerms.emptyHint (using the
component's existing i18n/translation hook, e.g., t()) instead of only the
title/subtitle so users see "You haven't saved any explanations yet" and the
hint "Select any term in Q&A to get an AI explanation"; ensure the conditional
branch replaces or augments the current render path that shows title/subtitle
when hasTerms is false.

In `@frontend/components/dashboard/ExplainedTermsCard.tsx`:
- Around line 152-160: The icon-only buttons (the drag handle using
GripVertical, the remove button and the restore button) lack accessible names;
add aria-label attributes to each icon-only <button> (e.g., the drag handle that
calls handleDragStart(term) and checks draggedTerm) using the existing i18n
helper (use t(...) with contextual keys like t('ariaDragHandle', { term }),
t('ariaHide', { term }) and t('ariaRestore', { term })) so screen readers
receive a descriptive label that includes the term; ensure these aria-labels are
present on the buttons that only render icons and update any related tests/props
that expect these buttons to be labeled.
- Around line 143-177: The current list rendering uses key={term} in terms.map
which breaks reconciliation and DnD when duplicate strings occur; change the
component to use a stable unique key (e.g. `${term}-${index}` or an explicit id)
and modify the drag/drop handlers to operate on indices rather than indexOf:
update the map to pass the index into onDragStart and onDrop (referencing
terms.map, key={term}, handleDragStart, handleDrop) and update
handleDragStart/handleDrop to accept and use the sourceIndex/targetIndex for
reordering; alternatively deduplicate terms when loading from getCachedTerms()
so keys remain unique.

In `@frontend/messages/en.json`:
- Line 1033: Fix the typo in the JSON string value for the "content" key by
replacing "sctrictly" with "strictly" so the sentence reads "...for strictly
necessary DevLovers platform functionality."; update the value of the "content"
property accordingly.

In `@frontend/messages/pl.json`:
- Line 253: The translation for the key "builtWith" (footer.builtWith) is
incorrect: it currently reads "Zbudowane wokół" ("Built around") but should
match the English "Built by"; update the Polish value to a proper equivalent
such as "Zbudowane przez" so the translation semantics align with en.json.
🧹 Nitpick comments (8)
frontend/messages/uk.json (1)

937-946: Ukrainian pluralization missing for termCount.

"{count} термінів збережено" only works for counts ≥ 5. Ukrainian has three plural forms: "термін" (1), "терміни" (2–4), "термінів" (5+). If you're using next-intl, ICU {count, plural, ...} syntax handles this. Note that cartWithItems (line 25) has the same pre-existing issue, so this is consistent with current patterns — but worth addressing across the board.

Example ICU plural form
-"termCount": "{count} термінів збережено"
+"termCount": "{count, plural, one {# термін збережено} few {# терміни збережено} other {# термінів збережено}}"
frontend/components/header/MainSwitcher.tsx (1)

78-78: Consider extracting the growing condition into a named variable.

This ternary condition now chains four function calls. A named boolean would improve readability.

♻️ Suggested refactor
+  const isFullWidthPath = isQa || isHome || isQuizzesPath(pathname) || isDashboardPath(pathname);
+
   return (
-    <main className={isQa || isHome || isQuizzesPath(pathname) || isDashboardPath(pathname) ? 'mx-auto' : 'mx-auto min-h-[80vh] px-6'}>
+    <main className={isFullWidthPath ? 'mx-auto' : 'mx-auto min-h-[80vh] px-6'}>
       {children}
     </main>
   );
frontend/lib/ai/hiddenTerms.ts (1)

17-19: Add Array.isArray guard after parsing to prevent corrupted localStorage data from producing unexpected results.

If the stored value is not an array (e.g., a string from external tampering), new Set("hello") would yield Set { "h", "e", "l", "o" } instead of failing gracefully.

🛡️ Proposed fix
     const terms: string[] = JSON.parse(raw);
+    if (!Array.isArray(terms)) {
+      return new Set();
+    }
     return new Set(terms);
frontend/app/[locale]/dashboard/page.tsx (1)

99-106: Hardcoded Telegram URL — consider extracting to a config or environment variable.

The support link https://t.me/devloversteam is hardcoded. If this channel changes, it would require a code change and redeploy. Consider moving it to an environment variable or a shared constants file.

frontend/components/dashboard/ExplainedTermsCard.tsx (4)

74-88: Side effect inside state updater function.

saveTermOrder(newTerms) on line 86 is a side effect (localStorage write) inside the setTerms updater callback. React may call updater functions multiple times (e.g., in Strict Mode). Move the persistence call outside the updater.

♻️ Proposed fix
  const handleDrop = (targetTerm: string) => {
    if (!draggedTerm || draggedTerm === targetTerm) {
      setDraggedTerm(null);
      return;
    }

-   setTerms(prevTerms => {
+   setTerms(prevTerms => {
      const newTerms = [...prevTerms];
      const draggedIndex = newTerms.indexOf(draggedTerm);
      const targetIndex = newTerms.indexOf(targetTerm);

      if (draggedIndex === -1 || targetIndex === -1) {
        return prevTerms;
      }

      newTerms.splice(draggedIndex, 1);
      newTerms.splice(targetIndex, 0, draggedTerm);

-     saveTermOrder(newTerms);
      return newTerms;
    });

    setDraggedTerm(null);
  };

Then persist in a useEffect that watches terms:

useEffect(() => {
  if (terms.length > 0) {
    saveTermOrder(terms);
  }
}, [terms]);

50-57: Same issue: side effect in setTerms updater at handleRestoreTerm.

saveTermOrder(updated) on line 55 is also inside a state updater. The same useEffect-based persistence approach from the previous comment would eliminate both.


182-232: Hidden terms section is always visible, even when no terms exist at all.

When a user has never used the explain feature, both terms and hiddenTerms will be empty, yet this collapsible section still renders showing "0 hidden terms." Consider hiding it when !hasTerms && !hasHiddenTerms.

♻️ Proposed fix
          {/* Explained Terms Section */}
+         {(hasTerms || hasHiddenTerms) && (
          <div className="mt-6">
              <button ...>
              ...
              </div>
+         )}

106-111: Template literal for cardStyles includes leading/trailing whitespace and newlines.

While Tailwind typically handles this fine, a cleaner approach is to use a single-line string or a utility like clsx/cn to avoid accidental whitespace in the class list.

Comment thread frontend/app/[locale]/dashboard/page.tsx
Comment thread frontend/components/dashboard/ExplainedTermsCard.tsx Outdated
Comment thread frontend/components/dashboard/ExplainedTermsCard.tsx
Comment thread frontend/messages/en.json Outdated
Comment thread frontend/messages/pl.json Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@frontend/components/dashboard/ExplainedTermsCard.tsx`:
- Around line 206-208: The hidden terms map uses key={term} which can collide
for duplicate values; update the map over hiddenTerms in ExplainedTermsCard (the
JSX block rendering hiddenTerms) to include the index parameter and set the key
to a stable combined string like `${term}-${index}` (matching the visible-terms
approach) so each rendered <div> has a unique key.

In `@frontend/messages/pl.json`:
- Around line 253-254: The Polish locale currently duplicates "przez" because
"builtWith" is "Zbudowane przez" while "byCommunity" remains "przez
społeczność."; update the "byCommunity" value to remove the leading "przez"
(e.g., change the value of the byCommunity key to "społeczność." or match
punctuation style used elsewhere) so the concatenation of builtWith +
byCommunity renders correctly; modify the JSON entry for the byCommunity key
accordingly.
🧹 Nitpick comments (1)
frontend/components/dashboard/ExplainedTermsCard.tsx (1)

68-84: draggedIndex is read from the outer closure inside a functional state updater.

setTerms(prevTerms => ...) correctly uses prevTerms for the array, but draggedIndex is captured from the enclosing scope. If React batches state updates, draggedIndex could theoretically be stale relative to prevTerms. Since handleDragStart and handleDrop are sequential user events, this works in practice, but using a ref for draggedIndex would be more robust.

Comment on lines +206 to +208
{hiddenTerms.map(term => (
<div
key={term}
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.

⚠️ Potential issue | 🟡 Minor

Hidden terms list uses key={term} — inconsistent with the visible-terms fix.

Visible terms at line 138 correctly use key={\${term}-${index}`}to avoid duplicate-key issues, but hidden terms here still usekey={term}`. Apply the same pattern for consistency and to prevent React key collisions if duplicate terms exist.

Proposed fix
-                        {hiddenTerms.map(term => (
+                        {hiddenTerms.map((term, index) => (
                           <div
-                            key={term}
+                            key={`${term}-${index}`}
                             className="group relative ..."
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{hiddenTerms.map(term => (
<div
key={term}
{hiddenTerms.map((term, index) => (
<div
key={`${term}-${index}`}
🤖 Prompt for AI Agents
In `@frontend/components/dashboard/ExplainedTermsCard.tsx` around lines 206 - 208,
The hidden terms map uses key={term} which can collide for duplicate values;
update the map over hiddenTerms in ExplainedTermsCard (the JSX block rendering
hiddenTerms) to include the index parameter and set the key to a stable combined
string like `${term}-${index}` (matching the visible-terms approach) so each
rendered <div> has a unique key.

Comment thread frontend/messages/pl.json
Comment on lines +253 to 254
"builtWith": "Zbudowane przez",
"byCommunity": "przez społeczność.",
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.

⚠️ Potential issue | 🟡 Minor

Double "przez" — byCommunity needs updating to match the new builtWith.

With builtWith now set to "Zbudowane przez" and byCommunity still "przez społeczność.", the rendered text will read "Zbudowane przez przez społeczność." ("Built by by community.").

The English locale uses "Built by" + "community.", and the Ukrainian uses "Створено" + "спільнотою." — both avoid duplication. Update byCommunity here to drop the leading "przez":

Proposed fix
     "builtWith": "Zbudowane przez",
-    "byCommunity": "przez społeczność.",
+    "byCommunity": "społeczność.",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"builtWith": "Zbudowane przez",
"byCommunity": "przez społeczność.",
"builtWith": "Zbudowane przez",
"byCommunity": "społeczność.",
🤖 Prompt for AI Agents
In `@frontend/messages/pl.json` around lines 253 - 254, The Polish locale
currently duplicates "przez" because "builtWith" is "Zbudowane przez" while
"byCommunity" remains "przez społeczność."; update the "byCommunity" value to
remove the leading "przez" (e.g., change the value of the byCommunity key to
"społeczność." or match punctuation style used elsewhere) so the concatenation
of builtWith + byCommunity renders correctly; modify the JSON entry for the
byCommunity key accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants