You're a frontend engineer on the CoderX platform team. The course detail page needs a star rating widget so learners can rate how well a course taught the hands-on skill it promises. A teammate started the implementation (src/components/StarRating.jsx, backed by a custom hook plus a couple of pure helpers), but QA sent the ticket back with two open items:
- Clicking a star does nothing. The widget already renders and supports hover previews, but the click-to-commit behavior was never wired up — selecting a rating is core functionality. Finish it.
- The hover preview leaks into the stored rating. Hover over a star, then move the mouse away — the previewed value gets written back as the permanent rating instead of being thrown away. Committing a rating you only glanced at is a data-integrity bug. It lives in the rating state hook; read that file carefully.
Required behavior
- The widget renders exactly
max stars (default 5).
- Each star is rendered as a
<button class="star"> with a data-testid of star-1 … star-{max}. A star at or below the currently active value gets the filled class; the rest stay empty. A plus character ★ is already used as the star glyph — leave it.
- The widget root is
<div class="star-rating">, and it always exposes the committed rating via a data-rating attribute.
- Given an
initialValue prop (default 0), exactly that many stars render filled on first paint.
- Clicking star N permanently sets the rating to N, clamped between
0 and max, and clears any in-progress hover preview.
- Hovering star N only previews it: the stars light up to N while the pointer is over the row, but the committed
data-rating must not change.
- Moving the mouse off the star row discards the preview and reverts the display to the committed rating.
Files
src/components/Star.jsx — presentational star button. Already implemented; read it to learn its props.
src/components/StarRating.jsx — container that wires stars to state. handleClick is a stub — implement it.
src/hooks/useStarRating.js — rating / hover state. commit is a stub (implement it) and this file also contains the QA bug above (find and fix it). Don't confuse the two — fix the bug without "fixing" the todo.
src/utils/rating.js — pure helpers clampRating and getStarState. Already implemented.
src/App.jsx — page shell that renders the widget.
Notes
- The hidden test suite drives everything through
data-testid, the .star-rating root, its data-rating attribute, and the .star / .filled classes — don't rename any of these.
- Hover events fire on the star buttons; the "pointer left the row" handler is
onMouseLeave on .star-rating__row. Tests simulate those events directly.
- Keep styling minimal and functional — no new styling libraries, themes, or animations.
- The initial preview must stay rendering (heading + stars, no crash) the moment you open the challenge.