Skip to content

MSPCA-51 Add navbar to the app layout - #31

Draft
Juwang110 wants to merge 6 commits into
pk/mspca-46-animal-availability-frontend-endpointfrom
jw/mspca-51-navbar
Draft

Juwang110 wants to merge 6 commits into
pk/mspca-46-animal-availability-frontend-endpointfrom
jw/mspca-51-navbar

Conversation

@Juwang110

@Juwang110 Juwang110 commented Nov 6, 2026 •

Copy link
Copy Markdown

ℹ️ Issue

Closes MSPCA-51

Stacked on #30 (MSPCA-46). Once #30 merges, the base switches to main.

📝 Description

Adds the site navbar from the Figma header component: the MSPCA logo on the left, and the volunteer's avatar and "My Profile" on the right. It's rendered once in a shared layout, so every page gets it without importing it. Until sign-in exists, the current volunteer comes from a ?volunteerId= query param, e.g. /animal-availability?volunteerId=1.

  1. Navbar component (components/Navbar.tsx), built from the final "Header desktop" / "Header mobile" components rather than the older frame linked in the ticket. Desktop is 120px tall with a 196×88 logo, a 66px avatar and "My Profile", which underlines on hover. Below Chakra's md breakpoint the logo is 142×64, the avatar is 50px and "My Profile" is hidden, matching the mobile design.
  2. Volunteer info comes from GET /api/volunteers/:volunteerId through a new apiClient.getVolunteer. The avatar shows the volunteer's initials on a color picked from their ID, so each volunteer always gets the same color. With no ID, an invalid one (abc, 0, -3, or a number too large to be a real ID), or a failed request, the avatar is a plain gray circle. A failed request also logs a console warning.
  3. Shared layout. All routes are now children of containers/Layout.tsx. Unknown URLs render a "Page not found" message under the navbar instead of a blank error page, and if a page crashes, its error shows under the navbar too.
  4. useVolunteerId() (utils/useVolunteerId.ts) is the one place that reads the ID from the URL, so swapping it for the signed-in user later is a one-file change. AnimalModal now uses it instead of the hardcoded CURRENT_VOLUNTEER_ID = 1, and its Apply button is disabled when there's no ID.
  5. Removed PageHeader from the Animal Availability page, since the navbar replaces it. The page now fills the space under the navbar instead of being 100vh tall, which made it always scroll.

Decisions open to review:

  • Avatar colors are a placeholder (purple, blue, teal, green, orange, brown, chosen by volunteerId % 6). Figma only has the one purple, so I'll swap in Matt's colors when we have them. They're a single list in utils/volunteer.ts.
  • "My Profile" is a button that doesn't go anywhere yet, because there's no profile page.
  • The ID is a query param rather than part of the path, so no routes had to change and it's easy to remove once sign-in lands.

✔️ Verification

  • New tests cover the ID parsing and initials, the navbar (initials, gray avatar with no ID or a failed request, ignoring a slow response after the ID changes), the routes (navbar on each page, exactly once on Animal Availability, on the 404 page and when a page crashes), and AnimalModal sending the URL's ID. All 31 frontend tests pass, and lint and typecheck are clean.
  • I ran the app in a browser at 1440px and 402px wide and compared it to the Figma components. Sizes and positions match, there's no horizontal scroll on mobile, and the empty Animal Availability page no longer scrolls. The backend wasn't running, so the volunteer response was stubbed with the same shape the endpoint returns.
  • nx test frontend is still broken on this branch, as on main (parseCLI is not a function), so I ran npx vitest run in apps/frontend instead. The old app.spec.tsx "Welcome frontend" test was replaced with the route tests.
  • To try it, run the backend and frontend and open http://localhost:4200/animal-availability?volunteerId=1. If COGNITO_USER_POOL_ID and COGNITO_CLIENT_ID are set in .env, the sign-in form shows first, so comment them out and restart the dev server.

🏕️ (Optional) Future Work / Notes

  • Anyone can change ?volunteerId= and request a match as another volunteer. The old hardcoded 1 had the same problem. The real fix is for POST /matches to take the volunteer from the Cognito token instead of the request body, which fits with the sign-in ticket.
  • ?volunteerId= isn't carried over when you navigate within the app. There are no in-app links yet, so it doesn't matter today, and sign-in will replace it.
  • Without an ID, the Apply button in the animal modal is disabled with no explanation. That's fine for now since the param is temporary, but testers should know to add it.
  • app.spec.tsx logs a React act() warning from the Animal Availability page's data load. The tests still pass.

🤖 Generated with Claude Code

Juwang110 and others added 6 commits November 4, 2026 22:27
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Page render errors are now caught by a nested errorElement under the
layout, so the navbar stays visible. The layout is a full-height column
and the availability page fills the remaining space instead of 100vh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- parseVolunteerId rejects IDs above Number.MAX_SAFE_INTEGER, which
  previously turned into values like 1e+23
- Navbar logs a console warning when the volunteer request fails
- Restore the console.error spy in app.error.spec

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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