fix(frontend): standardize dashboard arrow icons (#973)#976
Conversation
… from i18n, add ArrowRight icons (#973) - Remove Unicode '→' from viewAll and viewHistory i18n keys in en/pl/de locales - Add ArrowRight lucide icon to CategoriesBrowse 'View all' link - Add ArrowRight lucide icon to NutritionTip 'Learn more' link - Fix double-arrow bug in RecentlyViewed 'View history' link (i18n '→' + icon) - All 4 dashboard navigation links now use consistent pattern: text + ArrowRight icon - Add 3 new tests verifying arrow icon presence and no text arrow artifacts - Update RecentlyViewed test mock to match new i18n values Closes #973
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📸 PR ScreenshotsCaptured 2 screenshots (1 mobile, 1 desktop) for 1 changed page(s):
📥 Download screenshots from workflow artifacts. Captured by PR Screenshots workflow • 2026-03-19 |
Bundle Size Report
✅ Bundle size is within acceptable limits. |
There was a problem hiding this comment.
Pull request overview
Standardizes dashboard “action link” arrows by removing Unicode right-arrow characters from i18n strings and rendering a consistent lucide-react <ArrowRight> icon in components, addressing the “double-arrow” bug.
Changes:
- Removed
→fromdashboard.viewAll/dashboard.viewHistoryinen/pl/demessage dictionaries. - Updated dashboard components to render a consistent
<ArrowRight>icon layout for “View all” and “Learn more”. - Updated/added unit tests to assert icon presence and absence of the Unicode arrow character.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/components/dashboard/RecentlyViewed.test.tsx | Updates i18n mock + adds assertion for icon/no Unicode arrow in “View history” link |
| frontend/src/components/dashboard/NutritionTip.tsx | Replaces hardcoded text arrow with <ArrowRight> icon and aligns link layout |
| frontend/src/components/dashboard/NutritionTip.test.tsx | Adds test ensuring icon arrow is used and Unicode arrow is absent |
| frontend/src/components/dashboard/CategoriesBrowse.tsx | Adds <ArrowRight> icon to “View all” link and updates link layout |
| frontend/src/components/dashboard/CategoriesBrowse.test.tsx | Adds test ensuring “View all” link includes SVG icon and no Unicode arrow |
| frontend/messages/en.json | Removes → from dashboard.viewAll / dashboard.viewHistory strings |
| frontend/messages/pl.json | Removes → from dashboard.viewAll / dashboard.viewHistory strings |
| frontend/messages/de.json | Removes → from dashboard.viewAll / dashboard.viewHistory strings |
| vi.mock("@/lib/i18n", () => ({ | ||
| useTranslation: () => ({ | ||
| t: (key: string) => { | ||
| const map: Record<string, string> = { | ||
| "dashboard.recentlyViewedCompact": "Recently Viewed", | ||
| "dashboard.viewAll": "View all", | ||
| "dashboard.viewHistory": "View history →", | ||
| "dashboard.viewHistory": "View history", | ||
| }; | ||
| return map[key] ?? key; |
There was a problem hiding this comment.
This file mocks useTranslation() with a hardcoded map, so the new “no text arrow” assertion won’t fail if messages/*.json accidentally reintroduce a → in dashboard.viewHistory. To actually guard against the original regression, consider using the real translate()/dictionary in this test (or add a small assertion that the locale value for dashboard.viewHistory does not contain →).
| render(<RecentlyViewed products={products} />); | ||
|
|
||
| const link = screen.getByRole("link", { name: /View history/ }); | ||
| expect(link.querySelector("svg")).toBeInTheDocument(); |
There was a problem hiding this comment.
The test name says “single arrow icon”, but the assertion only checks that an svg exists. If a future change renders multiple SVGs inside the link (or reintroduces a double-icon bug), this test would still pass; consider asserting the SVG count is exactly 1 for this link.
| expect(link.querySelector("svg")).toBeInTheDocument(); | |
| const svgs = link.querySelectorAll("svg"); | |
| expect(svgs).toHaveLength(1); |
| it("learn more link uses icon arrow instead of text arrow", () => { | ||
| render(<NutritionTip />); | ||
| const link = screen.getByText(/Learn more/); | ||
| expect(link.querySelector("svg")).toBeInTheDocument(); |
There was a problem hiding this comment.
This test verifies an svg exists, but it doesn’t assert that there’s exactly one icon in the link. If multiple SVGs get rendered inside the anchor, the test would still pass; consider asserting the SVG count is exactly 1.
| expect(link.querySelector("svg")).toBeInTheDocument(); | |
| const svgs = link.querySelectorAll("svg"); | |
| expect(svgs).toHaveLength(1); |
| (l) => l.getAttribute("href") === "/app/categories", | ||
| ); | ||
| expect(viewAll).toBeDefined(); | ||
| expect(viewAll!.querySelector("svg")).toBeInTheDocument(); |
There was a problem hiding this comment.
The test checks that a link contains an svg, but it doesn’t assert it’s the only icon within that link. To make the “no double arrow” intent more robust, consider asserting querySelectorAll("svg") has length 1 for the /app/categories link.
| expect(viewAll!.querySelector("svg")).toBeInTheDocument(); | |
| const svgs = viewAll!.querySelectorAll("svg"); | |
| expect(svgs.length).toBe(1); | |
| expect(svgs[0]).toBeInTheDocument(); |
| "newInCategory": "New {category}", | ||
| "viewAll": "View all →", | ||
| "viewHistory": "View history →", | ||
| "viewAll": "View all", | ||
| "viewHistory": "View history", |
There was a problem hiding this comment.
dashboard.viewAll is also used by RecentComparisons.tsx (link to /app/compare) which currently does not render an <ArrowRight> icon. After removing the → from this translation, that “View all” link will lose its arrow entirely, reintroducing inconsistency on the dashboard. Consider adding the icon there as well, or splitting the i18n keys so only icon-suffixed links use the arrowless label.
Summary
Fixes the double-arrow bug in the dashboard "View history" link and standardizes all 4 dashboard navigation links to use a consistent
lucide-react<ArrowRight>icon instead of mixed text arrows.Closes #973 | Part of Epic #972
Problem
The dashboard had 4 different arrow patterns across its navigation links:
RecentlyViewed"→"+<ArrowRight>icon→ →CategoriesBrowse"→"only (text)NutritionTip→in JSXQuickWinCard<ArrowRight>icon onlyScreenshot evidence: "View history → →" double arrow clearly visible in mobile dashboard screenshots (see issue #973).
Fix
Standardized pattern:
{t("key")} <ArrowRight className="h-3 w-3" aria-hidden="true" />i18n changes (3 locale files × 2 keys = 6 string edits)
→fromdashboard.viewAllanddashboard.viewHistoryinen.json,pl.json,de.jsonComponent changes
ArrowRightimport fromlucide-react, added icon to "View all" link withinline-flex items-center gap-1layoutArrowRightimport fromlucide-react, replaced hardcoded→with<ArrowRight>icon, changed link toinline-flex items-center gap-1layout<ArrowRight>icon; removing→from i18n fixes the double arrowTest changes
→), added test verifying single SVG icon and no text arrowAfter (all 4 links standardized)
{t("viewHistory")}+<ArrowRight>View history →(single icon) ✅{t("viewAll")}+<ArrowRight>View all →(icon) ✅{t("tipLearnMore")}+<ArrowRight>Learn more →(icon) ✅{t("quickWinViewSwap")}+<ArrowRight>View healthier option →(icon) ✅Verification
8 files changed, +48 / -12 lines