deckhearth/lib
Randall Stillwell 2e68574393 convoy: enable no-undef ESLint rule + fix 3 latent bugs it surfaced
PR #144 (`31da384`, 2026-06-13) shipped a `ReferenceError: useFocusTrap
is not defined` to production because the flat ESLint config did NOT
enable the core `no-undef` rule — only `react/jsx-no-undef` (which
catches undefined JSX components, not plain JS identifier references).
This PR closes that gap, narrowly.

## What changes

- `eslint.config.mjs`: enable `no-undef: 'error'` for source files +
  define the ~40 browser / Node / Vitest globals the rule needs.
  Hand-curated globals list (rejected pulling in the `globals` npm
  package for one config block).
- 3 latent bugs surfaced + fixed (NOT silenced with disables):

  | Site | Bug | Fix |
  |------|-----|-----|
  | `components/CollectionPageView.js:238` | `onClick={toggleFavorite}` — fn defined in `lib/use-collection-view.js:269` (collection-level favorite) but missing from the hook's `return {}` | Added to hook return + component destructure |
  | `components/CollectionPageView.js:532` | `onTogglePublic={togglePublic}` — same pattern, fn at line 315 of the hook | Same shape: hook return + destructure |
  | `components/ShareModal.js:99` | `fetchInvitedUsers()` scoped inside the useEffect body but called from `handleInvite` outside | Extracted to component scope via `useCallback`; effect dep array updated |

  Bugs 1 + 2 broke the "Favorite collection" button and the public-toggle
  in the Share modal on the collection-detail page. Bug 3 broke the
  "refresh invitee list" path after a successful invite. None had been
  flagged because the operator hadn't exercised those exact flows since
  the relevant hooks were last refactored.
- `components/ShareModal.js`: also adds an eslint-disable for
  `react-hooks/set-state-in-effect` on the moved `fetchInvitedUsers()`
  call. Matches the canonical pattern in `pages/profile.js:90` —
  async fetch; setState fires post-resolve, not synchronously to the
  effect body.

## Why not pull in @eslint/js/recommended wholesale?

The recommended bundle also enables `no-unused-vars`,
`no-prototype-builtins`, `no-empty`, `no-cond-assign`, and ~10 others
— each would generate dozens of pre-existing violations on this
codebase. The right rule-by-rule sweep is the deferred
`adopt-eslint-recommended-set` convoy. This PR is scoped to the one
rule that would have caught PR #144's bug class.

## Test plan

- [x] `npm run lint` — clean (1 pre-existing unrelated warning on
      `CollectionsPageView.js`'s `eslint-disable` directive — out of
      scope)
- [x] `npm run test:run` — 25 files / 123 tests pass
- [ ] CI on this PR
- [ ] Post-merge: exercise the three formerly-broken paths (favorite a
      collection from its detail page; toggle a collection public via
      Share modal; invite a user and confirm the invitee list refreshes)

## Convoy doc

`.convoys/enable-no-undef-eslint-rule.md` documents the surfaced bugs,
D1 (no-undef only vs recommended bundle), D2 (hand-curated globals vs
`globals` package), risks, and acceptance.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-13 01:17:18 -05:00
..
card-import Normalize collector numbers in catalog match and harden scanner adds. (#53) 2026-05-28 14:45:55 -05:00
flags bootstrap: agent pipeline v0.5.0 + ship-readiness review 2026-05-23 02:31:26 -05:00
auth-secret.js fix(auth): centralize JWT secret + 24h TTL (Brief 1 of fix-auth-bypass) 2026-05-23 10:40:50 -05:00
card-catalog-match.js Normalize collector numbers in catalog match and harden scanner adds. (#53) 2026-05-28 14:45:55 -05:00
card-number-utils.js Normalize collector numbers in catalog match and harden scanner adds. (#53) 2026-05-28 14:45:55 -05:00
card-text-match.js fix(scanner): Layer-1 SQL, printing picker, and rate-limit storm (#39) 2026-05-27 13:10:46 -05:00
collection-cards-csv.js Extract collection CSV export helper (Brief 1). (#80) 2026-06-03 16:53:01 -05:00
collection-tag-input.js Extract CollectionsCreateModal and tag helpers (Brief 1). (#82) 2026-06-03 16:53:08 -05:00
collection-vocabulary.js Vocabulary cleanup follow-up (#55) 2026-05-29 10:01:03 -05:00
deck-builder-stats.js refactor(deck-builder): extract stats lib and stats bar (Brief 1) (#89) 2026-06-03 17:24:40 -05:00
deck-detail-grouping.js refactor(deck): extract grouping lib and stats sidebar (Brief 1) (#137) 2026-06-13 00:44:16 -05:00
deck-format-utils.js refactor(decks): extract format utils and create modal (Brief 1) (#136) 2026-06-13 00:44:13 -05:00
mana-symbols.js Major Scanner Improvements 2025-07-29 14:19:48 -05:00
ocr-worker.js feat(scanner): AI Gateway vision + Layer-1 Tesseract/pg_trgm OCR (#38) 2026-05-27 12:59:59 -05:00
permission-middleware.js refactor(auth): add withAdmin() wrapper for admin API routes. (#68) 2026-06-02 12:42:22 -05:00
rate-limit.js fix(security): stop leaking Gemini API key to browsers (#34) 2026-05-27 08:41:48 -05:00
scan-capture-upload.js refactor(scanner): extract disambiguation dialog and upload helpers. (#67) 2026-06-02 11:01:32 -05:00
scan-vision.js fix(scanner): catalog gap review path + not-listed disambiguation (#40) 2026-05-27 13:42:51 -05:00
scanner-card-detection.js refactor(scanner): extract camera lifecycle hook (Brief 4) (#71) 2026-06-02 15:44:56 -05:00
scanner-card-identify.js refactor(scanner): extract card identification pipeline (Brief 3) (#70) 2026-06-02 15:34:13 -05:00
scanner-route-api.js refactor(scanner): extract session and route API libs (page Brief 1) (#74) 2026-06-02 16:15:27 -05:00
scanner-session.js refactor(scanner): extract session and route API libs (page Brief 1) (#74) 2026-06-02 16:15:27 -05:00
slug-utils.js 🔗 Implement Collection Slug URLs 2025-07-26 22:06:52 -05:00
theme-context.js feat(design-system): sub-convoy #1 — corner-ember gradient + dark default (#102) 2026-06-04 10:48:49 -05:00
use-auth.js fix(lint): clear lib/config baseline and make CI lint blocking. (#63) 2026-06-02 01:03:42 -05:00
use-camera-scanner.js refactor(scanner): extract camera lifecycle hook (Brief 4) (#71) 2026-06-02 15:44:56 -05:00
use-card-detail.js refactor(card): useCardDetail + CardDetailView (Brief 3) (#86) 2026-06-03 17:10:13 -05:00
use-card-editor.js refactor(card-editor): useCardEditor + CardEditorView (Brief 3) (#94) 2026-06-03 18:18:31 -05:00
use-cards-page.js Extract AuthenticatedCards into hook + view (cards Brief 3). (#79) 2026-06-03 12:49:25 -05:00
use-collection-view.js convoy: enable no-undef ESLint rule + fix 3 latent bugs it surfaced 2026-06-13 01:17:18 -05:00
use-collections-page.js refactor(collections): useCollectionsPage + view (Brief 3) (#87) 2026-06-03 17:10:17 -05:00
use-daily-ember.js feat(design-system): redesign v2 #2 + #5 — sidebar pill, wordmark, Daily Ember (#103) 2026-06-04 10:59:44 -05:00
use-deck-builder.js refactor(deck-builder): useDeckBuilder + DeckBuilderView (Brief 3) (#93) 2026-06-03 18:18:28 -05:00
use-deck-detail.js refactor(deck): useDeckDetail + DeckDetailView (Brief 3) (#146) 2026-06-13 01:14:46 -05:00
use-decks-page.js refactor(decks): useDecksPage + DecksPageView (Brief 3) (#145) 2026-06-13 01:14:43 -05:00
use-focus-trap.js feat(design-system): Liquid Glass redesign portfolio — foundation + primitives + Layout (#95) 2026-06-03 20:12:33 -05:00
use-scanner-identification.js refactor(scanner): extract identification hook (Brief 5) (#72) 2026-06-02 15:59:03 -05:00
use-scanner-queue.js refactor(scanner): extract useScannerQueue hook (page Brief 2) (#75) 2026-06-02 21:28:24 -05:00