Resolving merge conflicts for (feat: add base routes for Map View, Admin Dashboard, and Workflow page) PR5#64
Resolving merge conflicts for (feat: add base routes for Map View, Admin Dashboard, and Workflow page) PR5#64SAUMILDHANKAR wants to merge 5 commits into
Conversation
📝 WalkthroughWalkthroughAdds React Router support, routed pages, a fixed side navigation, and shared styling for the new page shell. The app now renders ChangesRouter migration
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
src/pages/AdminPage.tsx (1)
1-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract a shared
PlaceholderPagecomponent.
AdminPageandWorkflowPage(and likely the upcomingNotFoundPage) 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 winConsider adding a
:focus-visiblestate for nav links.
.header-nav__linkdefines 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 winNo error boundary around lazy-loaded routes.
React.lazychunk failures (network blips, deploy-time cache mismatches) will throw during render with onlySuspensein 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 valueConsider moving icon spacing to
pages.cssinstead of inlinestyleobjects.Since
pages.cssis already imported and presumably defines.header-nav__linkstyles, the repeatedstyle={{ 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
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (9)
package.jsonsrc/App.tsxsrc/components/Layout/Header.tsxsrc/main.tsxsrc/pages/AdminPage.tsxsrc/pages/MapPage.tsxsrc/pages/NotFoundPage.tsxsrc/pages/WorkflowPage.tsxsrc/styles/pages.css
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).
057d58b to
40517f0
Compare
There was a problem hiding this comment.
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
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (9)
package.jsonsrc/App.tsxsrc/components/Layout/Header.tsxsrc/main.tsxsrc/pages/AdminPage.tsxsrc/pages/MapPage.tsxsrc/pages/NotFoundPage.tsxsrc/pages/WorkflowPage.tsxsrc/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
There was a problem hiding this comment.
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
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (9)
package.jsonsrc/App.tsxsrc/components/Layout/Header.tsxsrc/main.tsxsrc/pages/AdminPage.tsxsrc/pages/MapPage.tsxsrc/pages/NotFoundPage.tsxsrc/pages/WorkflowPage.tsxsrc/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.tsxRepository: OpenSourceFellows/map_dashboard_hackathon
Length of output: 290
🏁 Script executed:
#!/bin/bash sed -n '1,25p' src/App.tsx | cat -nRepository: OpenSourceFellows/map_dashboard_hackathon
Length of output: 1614
Remove the duplicate
Headerimport.src/App.tsx:2,15importsHeadertwice 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.
Appstill fetches map data and rendersMapContainer/LayerControlsoutsideRoutes, whileMapPagealready does the same. This makes/admin,/workflow, and 404 render with the map UI, and/maprenders 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.
There was a problem hiding this comment.
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 winOld map state/rendering was never removed — map now leaks onto every route and duplicates on
/map.
layers/layerVisibilitystate, the collection-loading effect (Lines 37-85), and the direct<MapContainer>(Line 114) /<LayerControls>(Lines 134-137) are still rendered unconditionally, outside<Routes>. SinceMapPage(src/pages/MapPage.tsx) independently owns this same state and renders its ownMapContainer/LayerControls, this means:
/admin,/workflow, and the 404 page will still show the map + layer controls behind/around the routed placeholder content./mapwill render two separateMapContainerinstances (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
MapPageowns 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 winIcon-only buttons rely solely on
Tooltipfor an accessible name.Consider adding
aria-labelto eachIconButton(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 winHardcoded colors don't adapt to dark mode.
isDarkMode/toggleModeare wired up, butborderRight(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'sbgcolor: '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-domis deprecated in React Router v7.
react-router-domis kept only as a backward-compatibility re-export and will be dropped in v8; the React Router team recommends importing directly fromreact-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
📒 Files selected for processing (4)
pnpm-workspace.yamlsrc/App.tsxsrc/components/Layout/Header.tsxsrc/components/Layout/SideNav.tsx
✅ Files skipped from review due to trivial changes (1)
- pnpm-workspace.yaml
| 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> | ||
| ); | ||
| } |
There was a problem hiding this comment.
📐 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.
| {/* 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> |
There was a problem hiding this comment.
🎯 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.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/components/Layout/SideNav.tsx (1)
23-23: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider
React.ReactNodeoverJSX.Elementfor the return type.
JSX.Elementexcludesnull, 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
📒 Files selected for processing (3)
src/App.tsxsrc/components/Layout/SideNav.tsxsrc/pages/AdminPage.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- src/App.tsx
| import { JSX, useContext, useState } from 'react'; | ||
| import { | ||
| Box, | ||
| IconButton, | ||
| Typography, | ||
| } from '@mui/material'; |
There was a problem hiding this comment.
📐 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.
| 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
Screencast.From.2026-07-02.14-38-10.mp4