fix(lint): resolve every eslint warning without suppressions

react-hooks/set-state-in-effect and react-hooks/purity had been demoted
to warnings "so CI passes", and CI ran without --max-warnings 0, so all
22 violations were invisible there. Both rules are back at error.

- Confetti is rolled once per mount instead of during render, where it
  re-rolled on every re-render and made pieces visibly jump.
- Loading flags are derived from a "last settled request" key rather than
  set synchronously inside an effect. That also adds the cancellation
  these fetches were missing, so a resolved request can no longer write
  into a unmounted or superseded view.
- Effect dependency arrays corrected; the two eslint-disable-line
  comments in Profile.tsx are gone, and the split of its two effects
  removes the guard that silently never re-ran.
- GameCompletionModal derives visibility from status instead of mirroring
  it into state, with a ref so the sound and localStorage write fire once.
- ValidationFeedback adjusts state during render, the documented pattern,
  instead of paying an extra committed render per link.
- The three react-refresh suppressions in ui/ are resolved properly by
  extracting the variants into their own modules, so the component files
  export only components. badgeVariants had no consumers and is no longer
  exported.
- Drops a stale eslint-disable directive in sw.js.

The lint script now fails on warnings so this cannot quietly regress.
This commit is contained in:
TehRiehlDeal committed 2026-09-09 19:59:10 -07:00
1 parent 70d53ed37d
commit 470a67607b
21 files changed
+337 -210

No files matched your search

+13 -7
View File
@@ -7,15 +7,21 @@ export default function ValidationFeedback() {
const validationError = useGameStore((s) => s.validationError);
const chain = useGameStore((s) => s.chain);
const [showCheck, setShowCheck] = useState(false);
const [flashedLength, setFlashedLength] = useState(0);
// Flash a green check when the chain grows (successful validation). Adjusting
// state during render is React's documented pattern for reacting to a changed
// value; doing it in an effect costs an extra committed render each link.
if (chain.length > 1 && chain.length !== flashedLength) {
setFlashedLength(chain.length);
setShowCheck(true);
}
// Flash a green check when chain grows (successful validation)
useEffect(() => {
if (chain.length > 1) {
setShowCheck(true);
const timer = setTimeout(() => setShowCheck(false), 600);
return () => clearTimeout(timer);
}
}, [chain.length]);
if (!showCheck) return;
const timer = setTimeout(() => setShowCheck(false), 600);
return () => clearTimeout(timer);
}, [showCheck]);
if (isValidating) {
return (