fix(search): distinguish UNKNOWN vs NOT-APPLICABLE Nutri-Score labels in filter panel (#980)#984
Conversation
… in filter panel (#980)
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📸 PR ScreenshotsCaptured 4 screenshots (2 mobile, 2 desktop) for 2 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
This PR improves the Search filter UX by distinguishing Nutri-Score values that are missing data (UNKNOWN) from those that are category-exempt (NOT-APPLICABLE), both in labeling and in chip styling.
Changes:
- Extend
nutriScoreLabel()to support a dedicated fallback forNOT-APPLICABLEwhile keepingUNKNOWNon the standard fallback path. - Add distinct
NUTRI_COLORSstyles forUNKNOWNvsNOT-APPLICABLE. - Update Search filter components + i18n (en/pl/de) and adjust/add tests to verify the new distinctions.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/lib/nutri-label.ts | Adds optional notApplicableFallback to distinguish NOT-APPLICABLE vs UNKNOWN labeling. |
| frontend/src/lib/nutri-label.test.ts | Adds unit tests covering the new 3-arg behavior. |
| frontend/src/lib/constants.ts | Introduces styles for UNKNOWN and NOT-APPLICABLE Nutri-Score chips. |
| frontend/src/components/search/FilterPanel.tsx | Passes distinct i18n labels for UNKNOWN vs NOT-APPLICABLE. |
| frontend/src/components/search/FilterPanel.test.tsx | Updates mock data + assertions for “Unknown” vs “Exempt”. |
| frontend/src/components/search/ActiveFilterChips.tsx | Updates chip labels to reflect UNKNOWN vs NOT-APPLICABLE distinction. |
| frontend/src/components/search/ActiveFilterChips.test.tsx | Updates/extends tests for new chip labels. |
| frontend/messages/en.json | Adds filters.unknown and filters.notApplicable. |
| frontend/messages/pl.json | Adds filters.unknown and filters.notApplicable. |
| frontend/messages/de.json | Adds filters.unknown and filters.notApplicable. |
| ); | ||
| }); | ||
|
|
||
| it("maps UNKNOWN to fallback (not notApplicableFallback)", () => { |
There was a problem hiding this comment.
The test name uses a confusing double negative: "maps UNKNOWN to fallback (not notApplicableFallback)". Rewording (e.g., "ignores notApplicableFallback") would make intent clearer and easier to scan in failures.
| it("maps UNKNOWN to fallback (not notApplicableFallback)", () => { | |
| it("uses general fallback for UNKNOWN (ignores notApplicableFallback)", () => { |
| expect(screen.getAllByText("Exempt").length).toBeGreaterThanOrEqual(1); | ||
| }); | ||
| // Raw DB value must NOT appear | ||
| expect(screen.queryAllByText(/NOT.APPLICABLE/i)).toHaveLength(0); |
There was a problem hiding this comment.
This regex uses a wildcard dot ("NOT.APPLICABLE") which will match any character between NOT and APPLICABLE. Using the literal hyphen (e.g., /NOT-APPLICABLE/i) would be more precise and communicates the intent of preventing the raw DB value from leaking into the UI.
| expect(screen.queryAllByText(/NOT.APPLICABLE/i)).toHaveLength(0); | |
| expect(screen.queryAllByText(/NOT-APPLICABLE/i)).toHaveLength(0); |
| onChange={onChange} | ||
| />, | ||
| ); | ||
| expect(screen.getByText("Nutri Unknown")).toBeTruthy(); |
There was a problem hiding this comment.
The new UNKNOWN chip test asserts the translated label renders, but it doesn’t assert that the raw value "UNKNOWN" is not shown (the NOT-APPLICABLE test does). Adding that assertion would better protect against regressions where raw DB values leak into the chip text.
| expect(screen.getByText("Nutri Unknown")).toBeTruthy(); | |
| expect(screen.getByText("Nutri Unknown")).toBeTruthy(); | |
| expect(screen.queryByText(/UNKNOWN/i)).toBeNull(); |
Summary
Closes #980 (child of Epic #979)
Previously, both
UNKNOWNandNOT-APPLICABLENutri-Score values displayed as a single generic fallback ("Not Rated"), losing valuable semantic distinction. Users couldn't tell whether a product was exempt from Nutri-Score (alcohol, infant formula) or simply had missing data.Changes
Core utility —
nutri-label.tsnotApplicableFallbacktonutriScoreLabel()NOT-APPLICABLE→ usesnotApplicableFallbackwhen provided, otherwise falls back tofallbackUNKNOWN→ always usesfallback(data-missing semantics)Visual distinction —
constants.tsUNKNOWN: solid muted chip (bg-surface-muted text-foreground-secondary)NOT-APPLICABLE: dashed-border transparent chip (border border-dashed border-strong bg-transparent text-foreground-muted)i18n — all 3 locales (en/pl/de)
filters.unknown: "Unknown" / "Nieznany" / "Unbekannt"filters.notApplicable: "Exempt" / "Nie dotyczy" / "Ausgenommen"Components
FilterPanel.tsx— updatednutriScoreLabelcall with 3 argsActiveFilterChips.tsx— updatednutriScoreLabelcall with 3 argsTests (10 new/updated)
nutri-label.test.ts— 3 new tests for 3-param signature behaviorFilterPanel.test.tsx— added UNKNOWN to mock data, replaced "Not Rated" test with "Exempt" + "Unknown" distinction testsActiveFilterChips.test.tsx— updated NOT-APPLICABLE test expectation, added new UNKNOWN testVerification
File Impact
10 files changed, +59 / -9 lines