Summary
8 pre-existing ESLint warnings remain after PR #252. All are warnings (not errors) so CI passes, but they degrade the dev experience: fast-refresh warnings cause full page reloads instead of hot-swaps when editing those files. None affect runtime correctness.
Priority
Low
Warnings
1. bodymap.jsx — 5× fast-refresh (lines 4, 29, 50, 87, 97)
app/src/lib/bodymap.jsx exports both React components (BodySVG, HeatmapBodySVG) and non-component symbols (MUSCLES, SHAPES, EX_DB, calcMuscles, useIsMobile, color constants). Fast Refresh requires component files to only export components.
Fix: Split into two files:
app/src/lib/bodymap.js — all constants and non-component exports (MUSCLES, SHAPES, EX_DB, calcMuscles, useIsMobile, PRIMARY_FILL, etc.)
app/src/lib/bodymap.jsx — only BodySVG and HeatmapBodySVG components (imports from the new .js file)
Then update all import sites across the codebase — currently ~15 files import from bodymap.jsx. Use a global search for from.*bodymap to find them all.
2. PageShell.jsx — 1× fast-refresh (line 8)
app/src/components/PageShell.jsx exports the nav shell component plus SectionLabel, PageHeading, PageTitle, AccentChip, StickyCta, BackButton, useNavHints, NavBtn.
Fix: Extract non-component exports to app/src/lib/pageShell.js (or keep in PageShell.jsx but mark the file as non-component with an ESLint disable comment — only acceptable if the split is impractical). useNavHints is a hook and could go to app/src/lib/hooks.js. The styled sub-components (SectionLabel, AccentChip etc.) are imported by most views — update all import sites.
3. theme.jsx — 1× fast-refresh (line 24)
app/src/theme.jsx exports ThemeProvider (component) and useTheme (hook).
Fix: Move useTheme to app/src/lib/hooks.js alongside the existing useDebouncedSearch and useFetch hooks. Update all import sites (useTheme is used in several components).
4. App.jsx — 1× setState-in-effect (line 52)
useEffect(() => {
if (session && !localStorage.getItem("wl-intro-seen")) setIntroOpen(true);
}, [session]);
setIntroOpen(true) is called synchronously inside the effect body. The lint rule react-hooks/set-state-in-effect flags this as a potential source of cascading renders.
Fix: Derive the initial value from useState initialiser instead of an effect:
const [introOpen, setIntroOpen] = useState(
() => !!session && !localStorage.getItem("wl-intro-seen")
);
Or, if session is not available at mount time (it comes from Supabase auth and may arrive asynchronously), keep the effect but verify whether a layout effect or a ref guard is more appropriate. Check App.jsx around line 45–55 for context before choosing an approach.
Files to touch
app/src/lib/bodymap.jsx → split
app/src/lib/bodymap.js → new file (constants/utils)
app/src/components/PageShell.jsx → extract non-component exports
app/src/theme.jsx → remove useTheme
app/src/lib/hooks.js → add useTheme
app/src/App.jsx → fix setState-in-effect
- All files importing from
bodymap.jsx, PageShell.jsx, or theme.jsx → update import paths
Acceptance criteria
Out of scope
- Any logic changes to the components themselves
- Adding new tests (existing suite covers the affected modules)
Summary
8 pre-existing ESLint warnings remain after PR #252. All are
warnings(not errors) so CI passes, but they degrade the dev experience: fast-refresh warnings cause full page reloads instead of hot-swaps when editing those files. None affect runtime correctness.Priority
Low
Warnings
1.
bodymap.jsx— 5× fast-refresh (lines 4, 29, 50, 87, 97)app/src/lib/bodymap.jsxexports both React components (BodySVG,HeatmapBodySVG) and non-component symbols (MUSCLES,SHAPES,EX_DB,calcMuscles,useIsMobile, color constants). Fast Refresh requires component files to only export components.Fix: Split into two files:
app/src/lib/bodymap.js— all constants and non-component exports (MUSCLES,SHAPES,EX_DB,calcMuscles,useIsMobile,PRIMARY_FILL, etc.)app/src/lib/bodymap.jsx— onlyBodySVGandHeatmapBodySVGcomponents (imports from the new.jsfile)Then update all import sites across the codebase — currently ~15 files import from
bodymap.jsx. Use a global search forfrom.*bodymapto find them all.2.
PageShell.jsx— 1× fast-refresh (line 8)app/src/components/PageShell.jsxexports the nav shell component plusSectionLabel,PageHeading,PageTitle,AccentChip,StickyCta,BackButton,useNavHints,NavBtn.Fix: Extract non-component exports to
app/src/lib/pageShell.js(or keep inPageShell.jsxbut mark the file as non-component with an ESLint disable comment — only acceptable if the split is impractical).useNavHintsis a hook and could go toapp/src/lib/hooks.js. The styled sub-components (SectionLabel,AccentChipetc.) are imported by most views — update all import sites.3.
theme.jsx— 1× fast-refresh (line 24)app/src/theme.jsxexportsThemeProvider(component) anduseTheme(hook).Fix: Move
useThemetoapp/src/lib/hooks.jsalongside the existinguseDebouncedSearchanduseFetchhooks. Update all import sites (useThemeis used in several components).4.
App.jsx— 1× setState-in-effect (line 52)setIntroOpen(true)is called synchronously inside the effect body. The lint rulereact-hooks/set-state-in-effectflags this as a potential source of cascading renders.Fix: Derive the initial value from
useStateinitialiser instead of an effect:Or, if
sessionis not available at mount time (it comes from Supabase auth and may arrive asynchronously), keep the effect but verify whether a layout effect or a ref guard is more appropriate. CheckApp.jsxaround line 45–55 for context before choosing an approach.Files to touch
app/src/lib/bodymap.jsx→ splitapp/src/lib/bodymap.js→ new file (constants/utils)app/src/components/PageShell.jsx→ extract non-component exportsapp/src/theme.jsx→ removeuseThemeapp/src/lib/hooks.js→ adduseThemeapp/src/App.jsx→ fix setState-in-effectbodymap.jsx,PageShell.jsx, ortheme.jsx→ update import pathsAcceptance criteria
npm run lintoutputs0 problems (0 errors, 0 warnings)npm teststill passes (91 tests)swa start)Out of scope