From ca84fb7da15dc6f62ceb17db51113b0ba16d4544 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 10 May 2026 01:34:20 +0200 Subject: [PATCH] feat(insights): thumbs-up/down feedback component with optimistic updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v1.4.16 phase B5e: ship the `` 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 ` + + + ); +}