Create useBansByCountry as the shared base hook containing all common fetch logic, abort-controller pattern, and state management. Both useDashboardCountryData and useMapData now wrap this base hook: - useDashboardCountryData: Thin wrapper that calls base hook with autoFetch=true - useMapData: Wraps base hook with 300ms debounce layer Changes: - Create useBansByCountry.ts (base hook with optional autoFetch parameter) - Refactor useDashboardCountryData.ts to use base hook - Refactor useMapData.ts to use base hook with debounce wrapper - Add tests for all three hooks Benefits: - Single source of truth for ban-by-country logic - Bug fixes in base hook apply to both consumers - Eliminates code duplication (~80 lines reduced) - Maintains backward compatibility: existing call sites work unchanged Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
4.8 KiB
T-18 · Merge useDashboardCountryData and useMapData — near-identical hooks
Where found: frontend/src/hooks/useDashboardCountryData.ts and frontend/src/hooks/useMapData.ts
Why this is needed: Both hooks call fetchBansByCountry, maintain the same state shape (countries, countryNames, bans, total, loading, error), and implement the same abort-controller pattern. The only behavioural difference is that useMapData adds a 300ms debounce. Any bug fix must be applied to both.
Goal: A single useBansByCountry base hook; useMapData adds the debounce on top.
What to do:
- Create
useBansByCountry(range, origin, source, countryCode?)— the shared fetch logic without debounce. - Refactor
useDashboardCountryDatato wrapuseBansByCountry. - Refactor
useMapDatato wrapuseBansByCountryand add the debounce layer. - Keep the existing hook names as thin wrappers to preserve call sites.
Possible traps and issues:
useMapDatareturns{ data }(the full response object) whereasuseDashboardCountryDataunpackscountries,countryNames,bans,total. Normalise the return shape before collapsing.- Tests for each hook test them independently — update or merge.
Docs changes needed: None.
Doc references: frontend/src/hooks/useDashboardCountryData.ts, frontend/src/hooks/useMapData.ts
T-19 · Move DashboardFilterProvider — page-scoped provider in wrong directory
Where found: frontend/src/providers/DashboardFilterProvider.tsx — instantiated only inside DashboardPage.tsx
Why this is needed: The providers/ directory implies app-wide providers (alongside AuthProvider, ThemeProvider, TimezoneProvider). DashboardFilterProvider wraps only DashboardPageContent and is not used anywhere else. Its placement implies reuse that doesn't exist, misleading future contributors about its scope.
Goal: Co-located with its only consumer.
What to do:
- Move
DashboardFilterProvider.tsxtofrontend/src/pages/(alongsideDashboardPage.tsx) or tofrontend/src/pages/dashboard/if the page is split into a subdirectory. - Update imports in
DashboardPage.tsxand any tests.
Possible traps and issues: Only DashboardPage.tsx imports it — confirm with grep before moving.
Docs changes needed: Docs/Web-Development.md — document what belongs in providers/ (app-wide) vs co-located.
Doc references: Docs/Web-Development.md
T-20 · Replace inline style={{}} objects with makeStyles classes
Where found: frontend/src/pages/map/MapBansTable.tsx (multiple), pages/JailDetailPage.tsx, pages/HistoryPage.tsx, pages/history/IpDetailView.tsx, components/WorldMap.tsx, components/TopCountriesPieChart.tsx, components/TopCountriesBarChart.tsx
Why this is needed: The project uses Fluent UI's makeStyles with atomic CSS caching. Inline style={{}} objects are allocated on every render, bypass the atomic CSS cache, and are inconsistent with the established pattern. Exceptions are acceptable only for truly dynamic values (e.g. tooltip left/top that change on mouse move) — static layout values must use makeStyles.
Goal: All static layout properties moved to makeStyles. Inline styles only for genuinely dynamic values.
What to do:
- Audit each file listed above.
- For static
display: flex,gap,margin,padding— move tomakeStylesin that component's style block. - Keep inline
styleonly where the value is truly dynamic at runtime (e.g.WorldMaptooltip position,TopCountriesBarChartchart height).
Possible traps and issues:
MapBansTable.tsxhas several consecutive inlinestyleobjects for its pagination row — these can be collapsed into one named class.- Some components use both
tokens.*values and inline styles — ensuremakeStylesis imported where it isn't already.
Docs changes needed: Docs/Web-Development.md — add styling rule: use makeStyles for all static styles; inline style only for runtime-dynamic values.
Doc references: Docs/Web-Development.md, Fluent UI v9 docs on makeStyles
T-21 · Fail2BanMetadataService has inline socket timeout hardcoded
Where found: backend/app/services/fail2ban_metadata_service.py:64 — socket_timeout: float = 5.0
Why this is needed: Part of the same constant duplication as T-08. This file doesn't use _SOCKET_TIMEOUT as a module constant — it hardcodes 5.0 inline as a local variable. Should use the constant from constants.py once T-08 is done.
Goal: After T-08, replace with FAIL2BAN_SOCKET_TIMEOUT_FAST import.
What to do: Covered by T-08 sweep.
Possible traps and issues: None — dependent on T-08.
Docs changes needed: None.
Doc references: backend/app/services/fail2ban_metadata_service.py