mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
v1.4.16 phase B5e: ship the `<RecommendationFeedback>` component that
plugs into the `data-slot="rec-feedback-slot"` reserved by B5c's
RecommendationCard. Two icon buttons (thumb-up / thumb-down) under
each rec; TanStack Query mutation against `/api/insights/feedback`.
State machine:
default → submitting-{up,down} → submitted-{up,down} (success)
→ already-rated-{up,down} (409)
→ default (network err, silent)
On success the buttons morph into a "Thanks for your feedback"
confirmation row with a green check + the chosen verdict's
glyph for context. On 409 (server says the user already rated this
exact rec text in a prior session) the row renders the prior
verdict highlighted and the buttons stay un-clickable — the
aggregator already has the signal.
Local cache via localStorage keyed on
`(userId, recId, truncatedRecText)` so a page refresh doesn't allow
re-rating before the server's 409 fires. The local cache is best-
effort; the server-side dedup (rec_feedback_user_rec_text_key
unique constraint) is the source of truth.
Auth-resolution race: when `useAuth()` returns null on first render
(in-flight fetch), the component re-syncs state from the local
cache during the next render — via setState-during-render, NOT
inside useEffect, to honour the project's
`react-hooks/set-state-in-effect` lint rule.
Accessibility: both buttons are real `<button type="button">`,
focusable, Enter/Space-activatable. aria-label translates to EN+DE.
i18n: 5 new keys under `insights.recommendation.*`:
feedbackHelpful, feedbackNotHelpful, feedbackThanks,
feedbackConfirmed, feedbackAlreadyRated.
EN+DE parity verified by the existing i18n parity guard.
6 component tests (renders both buttons, aria-labels, German labels,
submitted-up confirmation, already-rated highlight, type=button form
safety).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>