Skip to content

feat: Add base routes for Map View, Admin Dashboard, and Workflow page#5

Open
echelonnought wants to merge 1 commit into
mainfrom
feat/191-base-routes
Open

feat: Add base routes for Map View, Admin Dashboard, and Workflow page#5
echelonnought wants to merge 1 commit into
mainfrom
feat/191-base-routes

Conversation

@echelonnought
Copy link
Copy Markdown

@echelonnought echelonnought commented May 2, 2026

Summary

Implements the routing foundation for the Map Dashboard application as described in Issue #191.

Changes

New Files

  • src/pages/MapPage.tsx — Extracts existing map logic (MapContainer + LayerControls + layer state) from App.tsx into a dedicated page component
  • src/pages/AdminPage.tsx — Styled placeholder page for future admin dashboard functionality
  • src/pages/WorkflowPage.tsx — Styled placeholder page for future workflow management
  • src/pages/NotFoundPage.tsx — 404 page with a Back to Map navigation link
  • src/styles/pages.css — Styles for placeholder pages (floating animation, badges, dark mode support) and header navigation links

Modified Files

  • src/App.tsx — Replaced monolithic component with React Router setup using Routes, React.lazy(), and Suspense for code-splitting
  • src/main.tsx — Wrapped App with BrowserRouter to enable client-side routing
  • src/components/Layout/Header.tsx — Added NavLink navigation for Map, Admin, and Workflow routes with active state highlighting
  • package.json / pnpm-lock.yaml — Added react-router-dom dependency

Routes Configured

Route Component Behavior
/map MapPage Renders MapContainer + LayerControls (existing map functionality)
/admin AdminPage Styled placeholder with Coming Soon badge
/workflow WorkflowPage Styled placeholder with Coming Soon badge
/ Redirects to /map
* (catch-all) NotFoundPage 404 page with link back to map

Technical Details

  • All page components are lazy-loaded via React.lazy() + Suspense for optimal code splitting
  • Navigation uses NavLink from react-router-dom with CSS active state classes
  • Dark mode support included for all new pages and navigation styles
  • TypeScript compiles cleanly (tsc --noEmit exits with code 0)
  • Vite HMR confirmed working with no errors

Testing

  • / redirects to /map
  • /map renders the interactive map with layer controls
  • /admin shows styled placeholder
  • /workflow shows styled placeholder
  • Unknown routes show 404 page
  • Navigation links highlight active route
  • TypeScript type-check passes

Summary by CodeRabbit

  • New Features
    • Added multi-page navigation with dedicated sections for Map, Admin, and Workflow
    • Implemented header navigation with visual indicators for the active page
    • Added 404 error page for invalid or non-existent routes
    • Placeholder dashboards for Admin and Workflow features (coming soon)

Implements Issue #191 — Create base routes for Map View, Admin Dashboard, and Workflow page.

Changes:
- Install react-router-dom for client-side routing
- Wrap App with BrowserRouter in main.tsx
- Add React.lazy + Suspense for code-splitting all page components
- Create MapPage: extracts existing map logic from App.tsx (MapContainer + LayerControls)
- Create AdminPage: styled placeholder with 'Coming Soon' badge
- Create WorkflowPage: styled placeholder with 'Coming Soon' badge
- Create NotFoundPage: 404 page with 'Back to Map' link
- Configure routes: /map, /admin, /workflow, / → redirect to /map, * → 404
- Update Header with NavLink navigation (Map, Admin, Workflow) with active state
- Add pages.css for placeholder page styles and nav link styles

All routes lazy-loaded, TypeScript compiles cleanly (tsc --noEmit exit 0).
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

📝 Walkthrough

Walkthrough

This PR adds React Router to the application, converting it from a single-page map view to a multi-route application with lazy-loaded pages. Routes for /map, /admin, and /workflow are configured, with a fallback 404 page and header navigation links to traverse between pages.

Changes

Routing Architecture & Multi-Page Setup

Layer / File(s) Summary
Dependency & Entry Point
package.json, src/main.tsx
react-router-dom (v^7.14.2) is added as a dependency; BrowserRouter wraps <App /> in the root render.
App Routing Structure
src/App.tsx
App is rewritten to use Routes with four lazy-loaded page components (MapPage, AdminPage, WorkflowPage, NotFoundPage) mapped to /map, /admin, /workflow, and *; / redirects to /map.
Header Navigation
src/components/Layout/Header.tsx
Header now imports NavLink and navigation icons; a new <nav> section renders active-aware links to the three main routes with icon labels.
Page Components
src/pages/MapPage.tsx, src/pages/AdminPage.tsx, src/pages/WorkflowPage.tsx, src/pages/NotFoundPage.tsx
Four new page components are exported: MapPage loads and renders the map with layer controls (core functionality moved from old App); AdminPage, WorkflowPage, and NotFoundPage are placeholder layouts with styled typography, icons, and badges.
Page & Navigation Styling
src/styles/pages.css
New stylesheet defines placeholder layout styles (centered flex containers, animated icons, gradient badges), navigation bar layout, and active/hover states for header nav links with dark-mode overrides.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • OpenSourceFellows/map-dashboard#191: This PR directly implements the routing feature requested—adding react-router-dom dependency, wrapping App with BrowserRouter, converting App to lazy-loaded Routes for /map, /admin, /workflow with 404 fallback, creating MapPage/AdminPage/WorkflowPage components, and adding header navigation links.

Poem

🐰 Hop-skip through routes so neat,
NavLinks guide tired feet,
Lazy pages wait to load,
Router paves the app's new road.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly and clearly summarizes the main objective: adding base routes for three key pages (Map View, Admin Dashboard, and Workflow page).
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/191-base-routes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@echelonnought
Copy link
Copy Markdown
Author

Detailed Implementation Notes

What was done

This PR addresses Issue #191 — setting up the base routing structure for the Map Dashboard application. Here's a breakdown of every change and the reasoning behind it.


Architecture Decisions

1. React.lazy() + Suspense for code splitting
All page components are lazy-loaded rather than eagerly imported. This means the Admin and Workflow page bundles are only downloaded when a user actually navigates to those routes, keeping the initial map page load fast.

2. Page extraction pattern
The existing map logic (layer state, fixture loading, visibility toggling) was extracted from App.tsx into MapPage.tsx without any behavioral changes. App.tsx now only handles routing and layout — a cleaner separation of concerns.

3. NavLink with active state
The header uses NavLink from react-router-dom which automatically applies the header-nav__link--active CSS class to the current route's link. This gives users clear visual feedback about where they are.

4. 404 handling
Invalid routes show a styled NotFoundPage with a link back to /map rather than silently redirecting. This is better UX — users know they hit a bad URL and can recover.


Files Changed (10 files, +368 / -38 lines)

File Type What Changed
package.json Modified Added react-router-dom dependency
pnpm-lock.yaml Modified Lockfile update
src/main.tsx Modified Wrapped App with BrowserRouter
src/App.tsx Modified Replaced map logic with Routes + lazy loading
src/components/Layout/Header.tsx Modified Added nav links (Map, Admin, Workflow)
src/pages/MapPage.tsx New Map view with layer state management
src/pages/AdminPage.tsx New Admin placeholder
src/pages/WorkflowPage.tsx New Workflow placeholder
src/pages/NotFoundPage.tsx New 404 page
src/styles/pages.css New Placeholder + nav styles with dark mode

Verification

  • TypeScript compiles with zero errors (tsc --noEmit exit code 0)
  • Vite dev server runs with HMR, no console errors
  • All 5 routes tested and working locally

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/pages/MapPage.tsx`:
- Around line 19-29: The effect calling FixtureReader.collections() lacks error
handling and an unmount guard: catch promise rejections from
FixtureReader.collections() and handle errors (e.g., log or show fallback)
before attempting to setLayers or setLayerVisibility, and add a cleanup guard
(e.g., isMounted flag or AbortController) inside the useEffect so you only call
setLayers and setLayerVisibility (and construct the LayerVisibilityMap) when the
component is still mounted; ensure the promise chain uses .catch(...) and the
cleanup toggles the guard to prevent state updates after unmount.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ef30d0ff-1d7e-4aca-ad9f-ceaf5bb5238e

📥 Commits

Reviewing files that changed from the base of the PR and between c4ded60 and 057d58b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • package.json
  • src/App.tsx
  • src/components/Layout/Header.tsx
  • src/main.tsx
  • src/pages/AdminPage.tsx
  • src/pages/MapPage.tsx
  • src/pages/NotFoundPage.tsx
  • src/pages/WorkflowPage.tsx
  • src/styles/pages.css

Comment thread src/pages/MapPage.tsx
Comment on lines +19 to +29
useEffect(() => {
FixtureReader.collections()
.then(collections => {
setLayers([...collections]);

// Take the name property of each collection and set it's initial visibility to true
const layerNames = collections.map((fc) => fc.name);
const visibilityMap = layerNames.reduce((map, name) => { map[name] = true; return map; }, {} as LayerVisibilityMap);
setLayerVisibility({ ...visibilityMap });
});
}, []);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n --type ts 'FixtureReader\.collections\(|useEffect\(' src/pages src/data

Repository: OpenSourceFellows/map_dashboard_hackathon

Length of output: 187


🏁 Script executed:

cat -n src/pages/MapPage.tsx | head -50

Repository: OpenSourceFellows/map_dashboard_hackathon

Length of output: 1940


🏁 Script executed:

rg -n 'FixtureReader' src/ -A 5 -B 2

Repository: OpenSourceFellows/map_dashboard_hackathon

Length of output: 2305


🏁 Script executed:

fd -t ts -name 'FixtureReader*'

Repository: OpenSourceFellows/map_dashboard_hackathon

Length of output: 316


🏁 Script executed:

cat -n src/data/fixture-reader.ts

Repository: OpenSourceFellows/map_dashboard_hackathon

Length of output: 909


Handle fixture loading failures and unmounts.

FixtureReader.collections() is fire-and-forget here: a rejected fetch (line 13 of fixture-reader.ts throws on failed response) will surface as an unhandled promise rejection, and state updates can still run after the user navigates away from the map. Add a cleanup guard and .catch() handler before setting layers and layerVisibility.

♻️ Suggested fix
 useEffect(() => {
-    FixtureReader.collections()
-      .then(collections => {
-        setLayers([...collections]);
-
-        // Take the name property of each collection and set it's initial visibility to true
-        const layerNames = collections.map((fc) => fc.name);
-        const visibilityMap = layerNames.reduce((map, name) => { map[name] = true; return map; }, {} as LayerVisibilityMap);
-        setLayerVisibility({ ...visibilityMap });
-      });
+    let cancelled = false;
+
+    FixtureReader.collections()
+      .then((collections) => {
+        if (cancelled) return;
+
+        setLayers(collections);
+        const visibilityMap = collections.reduce((map, fc) => {
+          map[fc.name] = true;
+          return map;
+        }, {} as LayerVisibilityMap);
+        setLayerVisibility(visibilityMap);
+      })
+      .catch((error) => {
+        console.error('Failed to load map layers', error);
+      });
+
+    return () => {
+      cancelled = true;
+    };
   }, []);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useEffect(() => {
FixtureReader.collections()
.then(collections => {
setLayers([...collections]);
// Take the name property of each collection and set it's initial visibility to true
const layerNames = collections.map((fc) => fc.name);
const visibilityMap = layerNames.reduce((map, name) => { map[name] = true; return map; }, {} as LayerVisibilityMap);
setLayerVisibility({ ...visibilityMap });
});
}, []);
useEffect(() => {
let cancelled = false;
FixtureReader.collections()
.then((collections) => {
if (cancelled) return;
setLayers(collections);
const visibilityMap = collections.reduce((map, fc) => {
map[fc.name] = true;
return map;
}, {} as LayerVisibilityMap);
setLayerVisibility(visibilityMap);
})
.catch((error) => {
console.error('Failed to load map layers', error);
});
return () => {
cancelled = true;
};
}, []);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/MapPage.tsx` around lines 19 - 29, The effect calling
FixtureReader.collections() lacks error handling and an unmount guard: catch
promise rejections from FixtureReader.collections() and handle errors (e.g., log
or show fallback) before attempting to setLayers or setLayerVisibility, and add
a cleanup guard (e.g., isMounted flag or AbortController) inside the useEffect
so you only call setLayers and setLayerVisibility (and construct the
LayerVisibilityMap) when the component is still mounted; ensure the promise
chain uses .catch(...) and the cleanup toggles the guard to prevent state
updates after unmount.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant