Skip to content

Resolving merge conflicts for (feat: add base routes for Map View, Admin Dashboard, and Workflow page) PR5#64

Open
SAUMILDHANKAR wants to merge 5 commits into
mainfrom
resolvingconflictsinPR#5
Open

Resolving merge conflicts for (feat: add base routes for Map View, Admin Dashboard, and Workflow page) PR5#64
SAUMILDHANKAR wants to merge 5 commits into
mainfrom
resolvingconflictsinPR#5

Conversation

@SAUMILDHANKAR

@SAUMILDHANKAR SAUMILDHANKAR commented Jul 1, 2026

Copy link
Copy Markdown
Contributor
Screencast.From.2026-07-02.14-38-10.mp4

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds React Router support, routed pages, a fixed side navigation, and shared styling for the new page shell. The app now renders /map, /admin, /workflow, and a fallback page through lazy-loaded routes.

Changes

Router migration

Layer / File(s) Summary
Router setup and app routes
package.json, pnpm-workspace.yaml, src/main.tsx, src/App.tsx
Adds react-router-dom, enables esbuild builds, wraps the app in BrowserRouter, and replaces in-place map rendering with lazy-loaded routes for /map, /admin, /workflow, /, and *.
Side navigation and theme toggle
src/components/Layout/Header.tsx, src/components/Layout/SideNav.tsx
Reworks the layout chrome into a fixed side navigation with route links, active-state styling, theme switching, and an account link.
Routed page components
src/pages/MapPage.tsx, src/pages/AdminPage.tsx, src/pages/WorkflowPage.tsx, src/pages/NotFoundPage.tsx
Adds the map page implementation plus placeholder admin, workflow, and not-found pages.
Page and navigation styles
src/styles/pages.css
Adds shared placeholder page styles and navigation link styles with dark-mode variants.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

  • OpenSourceFellows/map-dashboard#191: Adds the same route-based setup for /map, /admin, and /workflow with shared navigation and router wiring.

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title reflects the main change by mentioning the new base routes, though it includes extra merge-conflict/PR noise.
✨ 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 resolvingconflictsinPR#5

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

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
src/pages/AdminPage.tsx (1)

1-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract a shared PlaceholderPage component.

AdminPage and WorkflowPage (and likely the upcoming NotFoundPage) share identical markup/CSS classes, differing only in icon/title/description. Consolidating avoids drift as more placeholder pages are added.

♻️ Suggested shared component
// src/components/PlaceholderPage.tsx
import React from 'react';
import '`@/styles/pages.css`';

interface PlaceholderPageProps {
  icon: string;
  title: string;
  description: string;
}

export const PlaceholderPage: React.FC<PlaceholderPageProps> = ({ icon, title, description }) => (
  <div className="page-placeholder">
    <div className="page-placeholder__icon" aria-hidden="true">{icon}</div>
    <h1 className="page-placeholder__title">{title}</h1>
    <p className="page-placeholder__description">{description}</p>
    <div className="page-placeholder__badge">Coming Soon</div>
  </div>
);
// src/pages/AdminPage.tsx
import React from 'react';
import { PlaceholderPage } from '`@/components/PlaceholderPage`';

export const AdminPage: React.FC = () => (
  <PlaceholderPage
    icon="🛠️"
    title="Admin Dashboard"
    description="Administrative tools and user management will appear here."
  />
);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/AdminPage.tsx` around lines 1 - 22, The AdminPage markup duplicates
the same placeholder layout used by WorkflowPage and future placeholder screens,
so extract a shared PlaceholderPage component to centralize the repeated
CSS/classes and structure. Create a reusable PlaceholderPage with props for
icon, title, and description, then update AdminPage to render that component
instead of inline markup so all placeholder pages stay consistent and avoid
drift.
src/styles/pages.css (1)

95-114: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding a :focus-visible state for nav links.

.header-nav__link defines hover and active states but no distinct focus style, relying on the browser default outline for keyboard navigation of the primary nav.

♻️ Suggested addition
 .header-nav__link--active {
   background: rgba(102, 126, 234, 0.15);
   color: `#667eea`;
   font-weight: 600;
 }
+
+.header-nav__link:focus-visible {
+  outline: 2px solid `#667eea`;
+  outline-offset: 2px;
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/styles/pages.css` around lines 95 - 114, The .header-nav__link styles
cover hover and active states but miss an explicit keyboard focus treatment; add
a :focus-visible state alongside .header-nav__link, .header-nav__link:hover, and
.header-nav__link--active so primary nav links have a clear, consistent focus
style without relying on the browser default outline.
src/App.tsx (1)

20-42: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

No error boundary around lazy-loaded routes.

React.lazy chunk failures (network blips, deploy-time cache mismatches) will throw during render with only Suspense in place, and since there's no error boundary, the whole app will crash instead of showing a fallback UI.

🛡️ Suggested addition
+import { ErrorBoundary } from '`@/components/ErrorBoundary`'; // or a library like react-error-boundary
 ...
       <main className="main-content">
-        <Suspense fallback={...}>
-          <Routes>
-            ...
-          </Routes>
-        </Suspense>
+        <ErrorBoundary fallback={<div className="page-placeholder">Something went wrong loading this page.</div>}>
+          <Suspense fallback={...}>
+            <Routes>
+              ...
+            </Routes>
+          </Suspense>
+        </ErrorBoundary>
       </main>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/App.tsx` around lines 20 - 42, The lazy-loaded route tree in App is only
wrapped with Suspense, so chunk load failures can still crash the app during
render. Add an error boundary around the route content in App (around
Suspense/Routes) or introduce a dedicated boundary component so failures from
React.lazy-loaded pages like MapPage, AdminPage, WorkflowPage, and NotFoundPage
show a fallback UI instead of unmounting the app.
src/components/Layout/Header.tsx (1)

46-74: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider moving icon spacing to pages.css instead of inline style objects.

Since pages.css is already imported and presumably defines .header-nav__link styles, the repeated style={{ marginRight: 6, verticalAlign: 'middle' }} on each icon could be a CSS class for consistency with the rest of the nav styling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Layout/Header.tsx` around lines 46 - 74, Move the repeated
icon spacing styles out of the NavLink children in Header and into pages.css for
consistency. Add a reusable CSS rule for the header nav icons (or extend the
existing .header-nav__link styling) to handle the margin/vertical alignment,
then remove the inline style objects from the Map, Settings, and Workflow icons
in Header.tsx.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/pages/MapPage.tsx`:
- Around line 15-31: Persist the map layer state so it survives route
navigation: in MapPage, the local state created by useState for layers and
layerVisibility is reset on unmount and FixtureReader.collections() runs again
when returning to /map. Move this state higher than MapPage (or use a shared
store/context) and have MapPage consume it, or keep the route mounted, so the
selections and loaded fixtures remain available across navigation.

---

Nitpick comments:
In `@src/App.tsx`:
- Around line 20-42: The lazy-loaded route tree in App is only wrapped with
Suspense, so chunk load failures can still crash the app during render. Add an
error boundary around the route content in App (around Suspense/Routes) or
introduce a dedicated boundary component so failures from React.lazy-loaded
pages like MapPage, AdminPage, WorkflowPage, and NotFoundPage show a fallback UI
instead of unmounting the app.

In `@src/components/Layout/Header.tsx`:
- Around line 46-74: Move the repeated icon spacing styles out of the NavLink
children in Header and into pages.css for consistency. Add a reusable CSS rule
for the header nav icons (or extend the existing .header-nav__link styling) to
handle the margin/vertical alignment, then remove the inline style objects from
the Map, Settings, and Workflow icons in Header.tsx.

In `@src/pages/AdminPage.tsx`:
- Around line 1-22: The AdminPage markup duplicates the same placeholder layout
used by WorkflowPage and future placeholder screens, so extract a shared
PlaceholderPage component to centralize the repeated CSS/classes and structure.
Create a reusable PlaceholderPage with props for icon, title, and description,
then update AdminPage to render that component instead of inline markup so all
placeholder pages stay consistent and avoid drift.

In `@src/styles/pages.css`:
- Around line 95-114: The .header-nav__link styles cover hover and active states
but miss an explicit keyboard focus treatment; add a :focus-visible state
alongside .header-nav__link, .header-nav__link:hover, and
.header-nav__link--active so primary nav links have a clear, consistent focus
style without relying on the browser default outline.
🪄 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: 8a40d19d-62fe-427a-ba0c-4f2c503cb82d

📥 Commits

Reviewing files that changed from the base of the PR and between 1e14ae5 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
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).
@SAUMILDHANKAR SAUMILDHANKAR force-pushed the resolvingconflictsinPR#5 branch from 057d58b to 40517f0 Compare July 1, 2026 22:26

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/App.tsx`:
- Around line 40-88: App is still loading fixture data and rendering
MapContainer/LayerControls alongside Routes, which duplicates the map UI and
leaks it onto /admin, /workflow, and 404. Move the map-data loading and
rendering logic out of App and into MapPage so the route tree exclusively owns
page content, and ensure App only defines the router structure. Use the existing
App, MapPage, and layers/layerVisibility state logic to consolidate the shared
map setup in one place and remove the duplicate render path.
- Line 15: Remove the duplicate Header import in App and keep only one import
from the same module; the duplicate import causes compilation failure. Update
src/App.tsx so the Header symbol is imported once and used consistently wherever
it appears in the component.
🪄 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: a815641d-199d-4685-ab56-1531717bb06b

📥 Commits

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

⛔ 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
✅ Files skipped from review due to trivial changes (1)
  • src/pages/NotFoundPage.tsx
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/pages/AdminPage.tsx
  • src/pages/WorkflowPage.tsx
  • src/styles/pages.css
  • src/pages/MapPage.tsx
  • src/components/Layout/Header.tsx
  • package.json

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/App.tsx`:
- Around line 40-88: App is still loading fixture data and rendering
MapContainer/LayerControls alongside Routes, which duplicates the map UI and
leaks it onto /admin, /workflow, and 404. Move the map-data loading and
rendering logic out of App and into MapPage so the route tree exclusively owns
page content, and ensure App only defines the router structure. Use the existing
App, MapPage, and layers/layerVisibility state logic to consolidate the shared
map setup in one place and remove the duplicate render path.
- Line 15: Remove the duplicate Header import in App and keep only one import
from the same module; the duplicate import causes compilation failure. Update
src/App.tsx so the Header symbol is imported once and used consistently wherever
it appears in the component.
🪄 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: a815641d-199d-4685-ab56-1531717bb06b

📥 Commits

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

⛔ 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
✅ Files skipped from review due to trivial changes (1)
  • src/pages/NotFoundPage.tsx
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/pages/AdminPage.tsx
  • src/pages/WorkflowPage.tsx
  • src/styles/pages.css
  • src/pages/MapPage.tsx
  • src/components/Layout/Header.tsx
  • package.json
🛑 Comments failed to post (2)
src/App.tsx (2)

15-15: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify there is only one Header import in App.tsx.
rg -n "import \{ Header \} from '`@/components/Layout/Header`'" src/App.tsx

Repository: OpenSourceFellows/map_dashboard_hackathon

Length of output: 290


🏁 Script executed:

#!/bin/bash
sed -n '1,25p' src/App.tsx | cat -n

Repository: OpenSourceFellows/map_dashboard_hackathon

Length of output: 1614


Remove the duplicate Header import. src/App.tsx:2,15 imports Header twice from the same module, which will fail module compilation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/App.tsx` at line 15, Remove the duplicate Header import in App and keep
only one import from the same module; the duplicate import causes compilation
failure. Update src/App.tsx so the Header symbol is imported once and used
consistently wherever it appears in the component.

40-88: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Let the route tree own the page content.

App still fetches map data and renders MapContainer/LayerControls outside Routes, while MapPage already does the same. This makes /admin, /workflow, and 404 render with the map UI, and /map renders duplicate maps/controls.

Proposed cleanup
-import { useEffect, useState, type JSX } from 'react';
+import { type JSX } from 'react';
 import { Header } from '`@/components/Layout/Header`';
-import { MapContainer } from '`@/components/Map/MapContainer`';
-import { LayerControls } from '`@/components/Map/LayerControls`';
 import { Box } from '`@mui/material`';
 import { GlobalStyles, useTheme } from '`@mui/material`';
@@
-import { FixtureReader } from './data/fixture-reader';
-import type { LayerVisibilityMap } from './types/map';
-import type { FeatureCollection } from './types/geometry';
 import { Suspense, lazy } from 'react';
@@
-  const [layers, setLayers] = useState<FeatureCollection[]>([])
-  const [layerVisibility, setLayerVisibility] = useState<LayerVisibilityMap>({})
@@
-  useEffect(() => {
-    async function loadCollections() {
-      const collections: FeatureCollection[] = await FixtureReader.collections();
-      const allLayers = [... collections];
-      setLayers(allLayers);
-      const layerNames = allLayers.map((layer) => layer.name);
-      const initialVisibility: LayerVisibilityMap = layerNames.reduce(
-        (map, name) => {
-          map[name] = true;
-          return map;
-        },
-        {} as LayerVisibilityMap
-      );
-      setLayerVisibility(initialVisibility);
-    }
-
-    loadCollections();
-    }, 
-    []
-  )
-
-  const layersToRender = layers.filter((layer) => layerVisibility[layer.name])
@@
-          <MapContainer layers={layersToRender} />
-          {/*<MapLegend />*/}
           <Suspense fallback={<div className="page-placeholder"><div className="page-placeholder__icon">⏳</div><p>Loading...</p></div>}>
             <Routes>
@@
             </Routes>
           </Suspense>
-          <LayerControls
-            visibilityMap={layerVisibility}
-            onLayerChange={setLayerVisibility}
-          />

Also applies to: 117-140

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/App.tsx` around lines 40 - 88, App is still loading fixture data and
rendering MapContainer/LayerControls alongside Routes, which duplicates the map
UI and leaks it onto /admin, /workflow, and 404. Move the map-data loading and
rendering logic out of App and into MapPage so the route tree exclusively owns
page content, and ensure App only defines the router structure. Use the existing
App, MapPage, and layers/layerVisibility state logic to consolidate the shared
map setup in one place and remove the duplicate render path.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/App.tsx (1)

37-85: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Old map state/rendering was never removed — map now leaks onto every route and duplicates on /map.

layers/layerVisibility state, the collection-loading effect (Lines 37-85), and the direct <MapContainer> (Line 114) / <LayerControls> (Lines 134-137) are still rendered unconditionally, outside <Routes>. Since MapPage (src/pages/MapPage.tsx) independently owns this same state and renders its own MapContainer/LayerControls, this means:

  • /admin, /workflow, and the 404 page will still show the map + layer controls behind/around the routed placeholder content.
  • /map will render two separate MapContainer instances (double data fetch, double Leaflet map mount).

The line-range summary states this direct rendering was "replaced" by the Routes tree, but the code shown still contains it — this looks like leftover code from the merge-conflict resolution that needs to be deleted now that MapPage owns this responsibility.

🐛 Proposed fix
-  /*
-   * layers: an array of map feature collections (initially empty)
-   * - FeatureCollection items contain geo-spatial types (points, lines, polygons) with coordinates
-   * setLayers: function to update the layers array, based on previous state
-   */
-  const [layers, setLayers] = useState<FeatureCollection[]>([])
-
-
-  /*
-   * layerVisibility: an object mapping each layer name to a boolean indicating whether it is visible on the map
-   * ...
-   */
-  const [layerVisibility, setLayerVisibility] = useState<LayerVisibilityMap>({})
-
-
-  /* Access the current MUI theme (light/dark mode) */
+  /* Access the current MUI theme (light/dark mode) */
   const theme = useTheme();
-
-
-  /* Load map feature collections once on component mount */
-  useEffect(() => {
-    ... (loadCollections body) ...
-    }, 
-    [] // dependency array
-  )
-
-  /* Logic to only render layers with visibility of `true` */
-  const layersToRender = layers.filter((layer) => layerVisibility[layer.name])
         <Box component="main" className="main-wrapper" sx={{ flex: 1, position: 'relative', overflow: 'hidden' }}>
-          <MapContainer layers={layersToRender} />
-          {/*<MapLegend />*/}
           <Suspense fallback={...}>
             <Routes>
               ...
             </Routes>
           </Suspense>
-          <LayerControls
-            visibilityMap={layerVisibility}
-            onLayerChange={setLayerVisibility}
-          />
         </Box>

Also applies to: 108-137

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/App.tsx` around lines 37 - 85, The app still keeps old map ownership in
App, so remove the redundant layers/layerVisibility state, the
FixtureReader.collections() loading effect, and the unconditional
MapContainer/LayerControls rendering from App since MapPage now owns that logic.
Keep App focused on the Routes tree and let MapPage be the only place that
fetches and renders the map/layer controls to avoid the map appearing on every
route and mounting twice on /map.
🧹 Nitpick comments (3)
src/components/Layout/SideNav.tsx (2)

87-162: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Icon-only buttons rely solely on Tooltip for an accessible name.

Consider adding aria-label to each IconButton (matching the tooltip text) so screen readers reliably announce the button's purpose without depending on hover/focus-triggered tooltip timing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Layout/SideNav.tsx` around lines 87 - 162, The icon-only
controls in SideNav rely only on Tooltip for their accessible name, so add
explicit aria-labels to each IconButton using the same text shown in the
tooltip. Update the NavLink-rendered IconButton instances in the navItems loop,
the theme toggle button, and the account/profile button so screen readers
announce their purpose without depending on Tooltip behavior.

43-163: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Hardcoded colors don't adapt to dark mode.

isDarkMode/toggleMode are wired up, but borderRight (Line 47), boxShadow (Line 48), active/hover backgrounds (Lines 102-108), and the profile button colors (Lines 149-152) are all fixed hex/rgba values tuned for light mode. Only the outer container's bgcolor: 'background.paper' (Line 46) is theme-aware. Toggling dark mode will leave a light-tinted border, shadow, and active/hover states clashing with the dark background.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Layout/SideNav.tsx` around lines 43 - 163, The SideNav styling
uses fixed hex/rgba values that stay light in dark mode, so the border, shadow,
active/hover states, and profile button colors clash with the theme. Update the
styling in SideNav’s main container and the NavLink/IconButton blocks to use
theme-aware palette values or conditional colors based on isDarkMode instead of
hardcoded light-mode colors. Focus on the borderRight, boxShadow, the
active/hover sx for nav items, and the profile/account button styling so all
states adapt consistently when toggleMode switches themes.
src/App.tsx (1)

14-14: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

react-router-dom is deprecated in React Router v7.

react-router-dom is kept only as a backward-compatibility re-export and will be dropped in v8; the React Router team recommends importing directly from react-router. Worth migrating now to avoid breakage on a future major bump.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/App.tsx` at line 14, The App routing import is using the deprecated
react-router-dom re-export; update the import in App.tsx to use react-router
directly instead. Keep the existing Routes, Route, and Navigate usage unchanged,
and make sure any other routing imports in App are aligned with the React Router
v7 recommended package so the app no longer depends on the compatibility layer.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/Layout/Header.tsx`:
- Around line 1-165: This file is a duplicate of the SideNav implementation and
should not keep an identical copy under the Header.tsx name. Remove the
duplicate default export SideNav here, or replace it with the intended distinct
Header component if one is still needed, so the logic remains centralized in the
existing SideNav component and does not drift. Use the SideNav default export,
ColorModeContext usage, and the NavLink/IconButton layout as the identifiers to
locate and reconcile the duplicate implementation.

In `@src/components/Layout/SideNav.tsx`:
- Around line 137-162: The SideNav profile link currently points to "/account",
but App routing does not define that path, so clicking it will always fall
through to NotFoundPage. Update the NavLink in SideNav to either target an
existing route like /admin or /workflow, or remove/disable the account button
until a matching /account route is added in App.tsx. Keep the fix aligned with
the existing NavLink and IconButton profile section so the active styling still
works correctly.

---

Outside diff comments:
In `@src/App.tsx`:
- Around line 37-85: The app still keeps old map ownership in App, so remove the
redundant layers/layerVisibility state, the FixtureReader.collections() loading
effect, and the unconditional MapContainer/LayerControls rendering from App
since MapPage now owns that logic. Keep App focused on the Routes tree and let
MapPage be the only place that fetches and renders the map/layer controls to
avoid the map appearing on every route and mounting twice on /map.

---

Nitpick comments:
In `@src/App.tsx`:
- Line 14: The App routing import is using the deprecated react-router-dom
re-export; update the import in App.tsx to use react-router directly instead.
Keep the existing Routes, Route, and Navigate usage unchanged, and make sure any
other routing imports in App are aligned with the React Router v7 recommended
package so the app no longer depends on the compatibility layer.

In `@src/components/Layout/SideNav.tsx`:
- Around line 87-162: The icon-only controls in SideNav rely only on Tooltip for
their accessible name, so add explicit aria-labels to each IconButton using the
same text shown in the tooltip. Update the NavLink-rendered IconButton instances
in the navItems loop, the theme toggle button, and the account/profile button so
screen readers announce their purpose without depending on Tooltip behavior.
- Around line 43-163: The SideNav styling uses fixed hex/rgba values that stay
light in dark mode, so the border, shadow, active/hover states, and profile
button colors clash with the theme. Update the styling in SideNav’s main
container and the NavLink/IconButton blocks to use theme-aware palette values or
conditional colors based on isDarkMode instead of hardcoded light-mode colors.
Focus on the borderRight, boxShadow, the active/hover sx for nav items, and the
profile/account button styling so all states adapt consistently when toggleMode
switches themes.
🪄 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: 90fea910-701c-406a-91ea-fec2c2279e6e

📥 Commits

Reviewing files that changed from the base of the PR and between 40517f0 and 1b478e8.

📒 Files selected for processing (4)
  • pnpm-workspace.yaml
  • src/App.tsx
  • src/components/Layout/Header.tsx
  • src/components/Layout/SideNav.tsx
✅ Files skipped from review due to trivial changes (1)
  • pnpm-workspace.yaml

Comment on lines +1 to 165
import { JSX, useContext } from 'react';
import { Box, IconButton, Tooltip } from '@mui/material';
import { NavLink } from 'react-router-dom';
import {
Globe,
FolderKanban,
Map,
Settings,
User,
Moon,
Sun,
} from 'lucide-react';

import { ColorModeContext } from '@/main';

const DRAWER_WIDTH = 86;

/* Renders the application header with branding and layout scaffolding.
* Includes a static light-mode theme toggle UI for styling and future interactivity.
*/
export function Header(): JSX.Element {
export default function SideNav(): JSX.Element {
const { mode, toggleMode } = useContext(ColorModeContext);
const isDarkMode = mode === 'dark';

const navItems = [
{
icon: <FolderKanban size={22} />,
path: '/',
label: 'Projects',
},
{
icon: <Map size={22} />,
path: '/map',
label: 'Map',
},
{
icon: <Settings size={22} />,
path: '/admin',
label: 'Admin',
},
];

return (
<Box
component="header"
className="header flex-row-align-center"
role="banner"
component="aside"
sx={{
justifyContent: 'space-between',
gap: 'var(--row-1)',
padding: 'var(--col-1) var(--col-1)',
width: DRAWER_WIDTH,
height: '100vh',
bgcolor: 'background.paper',
borderRight: '2px solid #E8E8E8',
boxShadow: '0px 20px 50px rgba(220,224,249,.5)',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
py: 2,
position: 'fixed',
left: 0,
top: 0,
zIndex: 1200,
}}
>
{/* Logo */}
<Box
component="a"
href="/"
className="header-logo flex-row-align-center"
aria-label="ProgramEarth"
sx={{
gap: 'var(--col-gutter)',
width: 44,
height: 44,
borderRadius: '50%',
background:
'linear-gradient(135deg,#6B73FF 0%, #8A63F6 100%)',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
color: 'white',
mb: 4,
}}
>
<Box
className="logo-icon flex-row-align-center"
sx={{
justifyContent: 'center',
}}
>
<Globe size={18} aria-hidden="true" />
</Box>
<h2 aria-hidden="true">ProgramEarth</h2>
<Globe size={22} />
</Box>

{/* Light / Dark Mode UI (static, light mode default) */}
{/* Menu */}
<Box
className="light-dark-container"
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: 'var(--row-1)',
ml: 'auto',
gap: 3,
flex: 1,
}}
>
<Box
className="light-dark-controller"
{navItems.map((item) => (
<Tooltip title={item.label} placement="right" key={item.path}>
<NavLink
to={item.path}
style={{ textDecoration: 'none' }}
>
{({ isActive }) => (
<IconButton
sx={{
width: 54,
height: 54,
borderRadius: '15px',
color: isActive
? '#3B82F6'
: 'text.secondary',
bgcolor: isActive
? '#EEF4FF'
: 'transparent',
transition: '0.2s',
'&:hover': {
bgcolor: '#EEF4FF',
},
}}
>
{item.icon}
</IconButton>
)}
</NavLink>
</Tooltip>
))}
</Box>

{/* Dark Mode */}
<Tooltip
title={isDarkMode ? 'Light Mode' : 'Dark Mode'}
placement="right"
>
<IconButton
onClick={toggleMode}
sx={{
display: 'flex',
alignItems: 'center',
gap: 'var(--row-gutter)',
width: 54,
height: 54,
borderRadius: '15px',
mb: 2,
}}
>
<Typography component="span" className="mode-label">
Dark Mode
</Typography>
{isDarkMode ? <Sun size={22} /> : <Moon size={22} />}
</IconButton>
</Tooltip>

<IconButton
id="theme-toggle"
className={`toggle-box ${isDarkMode ? 'toggle-box--active' : ''}`}
onClick={toggleMode}
aria-label={`Switch to ${isDarkMode ? 'light' : 'dark'} mode`}
role="switch"
aria-checked={isDarkMode}
disableRipple
sx={{
position: 'relative',
}}
>
<Box
className="toggle__slider"
{/* Profile */}
<Tooltip title="Account Settings" placement="right">
<NavLink
to="/account"
style={{ textDecoration: 'none' }}
>
{({ isActive }) => (
<IconButton
sx={{
top: '2px',
left: '2px',
position: 'absolute',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: 54,
height: 54,
borderRadius: '15px',
bgcolor: isActive
? '#82B1FF80'
: '#82B1FF40',
color: '#1E40AF',
'&:hover': {
bgcolor: '#82B1FF80',
},
}}
>
<Box className="toggle__icon">
<Moon size={18} />
</Box>
</Box>
</IconButton>
</Box>
</Box>
<User size={24} />
</IconButton>
)}
</NavLink>
</Tooltip>
</Box>
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Duplicate file: Header.tsx contains the exact SideNav implementation.

This file's default export is named SideNav and its content is identical to src/components/Layout/SideNav.tsx. App.tsx imports SideNav from @/components/Layout/SideNav, not from this file, so Header.tsx looks like a leftover duplicate from the merge-conflict resolution (PR #64). Having two files with identical component logic creates a drift risk — future edits to one won't be reflected in the other. This file should either be deleted, or if a Header component is still needed elsewhere, it should be restored to its own distinct implementation rather than duplicating SideNav.

🧰 Tools
🪛 React Doctor (0.5.8)

[error] 18-18: JSX.Element is too narrow: it excludes null, strings, numbers, and fragments that components commonly return. Use React.ReactNode instead.

Replace JSX.Element with React.ReactNode. JSX.Element is too narrow: it excludes null, strings, numbers, and fragments that components commonly return.

(no-jsx-element-type)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Layout/Header.tsx` around lines 1 - 165, This file is a
duplicate of the SideNav implementation and should not keep an identical copy
under the Header.tsx name. Remove the duplicate default export SideNav here, or
replace it with the intended distinct Header component if one is still needed,
so the logic remains centralized in the existing SideNav component and does not
drift. Use the SideNav default export, ColorModeContext usage, and the
NavLink/IconButton layout as the identifiers to locate and reconcile the
duplicate implementation.

Comment thread src/components/Layout/SideNav.tsx Outdated
Comment on lines +137 to +162
{/* Profile */}
<Tooltip title="Account Settings" placement="right">
<NavLink
to="/account"
style={{ textDecoration: 'none' }}
>
{({ isActive }) => (
<IconButton
sx={{
width: 54,
height: 54,
borderRadius: '15px',
bgcolor: isActive
? '#82B1FF80'
: '#82B1FF40',
color: '#1E40AF',
'&:hover': {
bgcolor: '#82B1FF80',
},
}}
>
<User size={24} />
</IconButton>
)}
</NavLink>
</Tooltip>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

"/account" has no matching route — will 404.

App.tsx only defines routes for /map, /admin, /workflow, / (redirects to /map), and a catch-all NotFoundPage. This NavLink to="/account" will therefore always resolve to NotFoundPage. Either add a placeholder /account route or disable/hide this link until the page exists.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Layout/SideNav.tsx` around lines 137 - 162, The SideNav
profile link currently points to "/account", but App routing does not define
that path, so clicking it will always fall through to NotFoundPage. Update the
NavLink in SideNav to either target an existing route like /admin or /workflow,
or remove/disable the account button until a matching /account route is added in
App.tsx. Keep the fix aligned with the existing NavLink and IconButton profile
section so the active styling still works correctly.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/components/Layout/SideNav.tsx (1)

23-23: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider React.ReactNode over JSX.Element for the return type.

JSX.Element excludes null, strings, and fragments that components may legitimately return, so it's narrower than necessary here (flagged by static analysis).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Layout/SideNav.tsx` at line 23, Update the SideNav component’s
return type from JSX.Element to React.ReactNode (or an equivalent broader React
return type) so it can legally return null, strings, or fragments if needed;
adjust the SideNav function signature accordingly and keep the component
behavior unchanged.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/Layout/SideNav.tsx`:
- Around line 1-6: Remove the unused IconButton import from SideNav; the profile
section now uses Box instead, so update the import list at the top of
SideNav.tsx to keep only the symbols actually referenced there, such as JSX,
useContext, useState, Box, and Typography.

---

Nitpick comments:
In `@src/components/Layout/SideNav.tsx`:
- Line 23: Update the SideNav component’s return type from JSX.Element to
React.ReactNode (or an equivalent broader React return type) so it can legally
return null, strings, or fragments if needed; adjust the SideNav function
signature accordingly and keep the component behavior unchanged.
🪄 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: 0bace900-6012-4652-8e15-69698151894a

📥 Commits

Reviewing files that changed from the base of the PR and between 1b478e8 and 3c528aa.

📒 Files selected for processing (3)
  • src/App.tsx
  • src/components/Layout/SideNav.tsx
  • src/pages/AdminPage.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/App.tsx

Comment on lines +1 to +6
import { JSX, useContext, useState } from 'react';
import {
Box,
IconButton,
Typography,
} from '@mui/material';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove unused IconButton import.

Static analysis flags IconButton as unused after the profile section was rewritten with a plain Box.

🧹 Proposed fix
 import {
   Box,
-  IconButton,
   Typography,
 } from '`@mui/material`';
📝 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
import { JSX, useContext, useState } from 'react';
import {
Box,
IconButton,
Typography,
} from '@mui/material';
import { JSX, useContext, useState } from 'react';
import {
Box,
Typography,
} from '`@mui/material`';
🧰 Tools
🪛 ESLint

[error] 4-4: 'IconButton' is defined but never used.

(@typescript-eslint/no-unused-vars)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Layout/SideNav.tsx` around lines 1 - 6, Remove the unused
IconButton import from SideNav; the profile section now uses Box instead, so
update the import list at the top of SideNav.tsx to keep only the symbols
actually referenced there, such as JSX, useContext, useState, Box, and
Typography.

Source: Linters/SAST tools

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.

2 participants